Skip to content

Commit ce08210

Browse files
feat: shaded lock spring
1 parent 839c5e7 commit ce08210

File tree

10 files changed

+402
-0
lines changed

10 files changed

+402
-0
lines changed

shaded-lock-ydb/pom.xml

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>tech.ydb.dialects</groupId>
8+
<artifactId>shaded-lock-ydb</artifactId>
9+
<version>0.9.1</version>
10+
11+
<packaging>jar</packaging>
12+
13+
<name>Shaded Lock Service YDB</name>
14+
<description>Shaded Lock Service YDB Spring Starter</description>
15+
<url>https://github.com/ydb-platform/ydb-java-dialects</url>
16+
17+
<developers>
18+
<developer>
19+
<name>Kirill Kurdyukov</name>
20+
<email>[email protected]</email>
21+
<organization>YDB</organization>
22+
<organizationUrl>https://ydb.tech/</organizationUrl>
23+
</developer>
24+
</developers>
25+
26+
<scm>
27+
<url>https://github.com/ydb-platform/ydb-java-dialects</url>
28+
<connection>scm:git:https://github.com/ydb-platform/ydb-java-dialects.git</connection>
29+
<developerConnection>scm:git:https://github.com/ydb-platform/ydb-java-dialects.git</developerConnection>
30+
</scm>
31+
32+
<properties>
33+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
34+
35+
<maven.compiler.release>17</maven.compiler.release>
36+
<maven.compiler.target>17</maven.compiler.target>
37+
<maven.compiler.source>17</maven.compiler.source>
38+
39+
<junit5.version>5.9.3</junit5.version>
40+
<log4j2.version>2.17.2</log4j2.version>
41+
<ydb.sdk.version>2.2.6</ydb.sdk.version>
42+
<ydb.jdbc.version>2.2.2</ydb.jdbc.version>
43+
<spring.boot.version>3.2.3</spring.boot.version>
44+
<shedlock-spring.version>5.15.0</shedlock-spring.version>
45+
</properties>
46+
47+
<licenses>
48+
<license>
49+
<name>Apache License, Version 2.0</name>
50+
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
51+
</license>
52+
</licenses>
53+
54+
<dependencyManagement>
55+
<dependencies>
56+
<dependency>
57+
<groupId>tech.ydb</groupId>
58+
<artifactId>ydb-sdk-bom</artifactId>
59+
<version>${ydb.sdk.version}</version>
60+
<type>pom</type>
61+
<scope>import</scope>
62+
</dependency>
63+
</dependencies>
64+
</dependencyManagement>
65+
66+
<dependencies>
67+
<dependency>
68+
<groupId>tech.ydb</groupId>
69+
<artifactId>ydb-sdk-coordination</artifactId>
70+
</dependency>
71+
<dependency>
72+
<groupId>net.javacrumbs.shedlock</groupId>
73+
<artifactId>shedlock-spring</artifactId>
74+
<version>${shedlock-spring.version}</version>
75+
<scope>provided</scope>
76+
</dependency>
77+
<dependency>
78+
<groupId>tech.ydb.jdbc</groupId>
79+
<artifactId>ydb-jdbc-driver</artifactId>
80+
<version>${ydb.jdbc.version}</version>
81+
<scope>provided</scope>
82+
</dependency>
83+
<dependency>
84+
<groupId>org.springframework.boot</groupId>
85+
<artifactId>spring-boot-autoconfigure</artifactId>
86+
<version>${spring.boot.version}</version>
87+
<scope>provided</scope>
88+
</dependency>
89+
90+
<dependency>
91+
<groupId>org.springframework.boot</groupId>
92+
<artifactId>spring-boot-starter-test</artifactId>
93+
<version>${spring.boot.version}</version>
94+
<scope>test</scope>
95+
</dependency>
96+
<dependency>
97+
<groupId>tech.ydb.test</groupId>
98+
<artifactId>ydb-junit5-support</artifactId>
99+
<scope>test</scope>
100+
</dependency>
101+
<dependency>
102+
<groupId>org.junit.jupiter</groupId>
103+
<artifactId>junit-jupiter-api</artifactId>
104+
<version>${junit5.version}</version>
105+
<scope>test</scope>
106+
</dependency>
107+
</dependencies>
108+
109+
<build>
110+
<plugins>
111+
<plugin>
112+
<groupId>org.apache.maven.plugins</groupId>
113+
<artifactId>maven-javadoc-plugin</artifactId>
114+
<version>3.5.0</version>
115+
<configuration>
116+
<source>17</source>
117+
</configuration>
118+
<executions>
119+
<execution>
120+
<id>attach-javadocs</id>
121+
<goals>
122+
<goal>jar</goal>
123+
</goals>
124+
</execution>
125+
</executions>
126+
</plugin>
127+
<plugin>
128+
<groupId>org.apache.maven.plugins</groupId>
129+
<artifactId>maven-source-plugin</artifactId>
130+
<version>3.2.1</version>
131+
<executions>
132+
<execution>
133+
<id>attach-sources</id>
134+
<goals>
135+
<goal>jar-no-fork</goal>
136+
</goals>
137+
</execution>
138+
</executions>
139+
</plugin>
140+
<plugin>
141+
<groupId>org.apache.maven.plugins</groupId>
142+
<artifactId>maven-surefire-plugin</artifactId>
143+
<version>3.1.0</version>
144+
<configuration>
145+
<environmentVariables>
146+
<TESTCONTAINERS_REUSE_ENABLE>true</TESTCONTAINERS_REUSE_ENABLE>
147+
</environmentVariables>
148+
</configuration>
149+
</plugin>
150+
</plugins>
151+
</build>
152+
153+
<profiles>
154+
<profile>
155+
<id>ossrh-s01</id>
156+
<activation>
157+
<activeByDefault>false</activeByDefault>
158+
</activation>
159+
160+
<build>
161+
<plugins>
162+
<plugin>
163+
<groupId>org.apache.maven.plugins</groupId>
164+
<artifactId>maven-gpg-plugin</artifactId>
165+
<version>3.1.0</version>
166+
<executions>
167+
<execution>
168+
<id>sign-artifacts</id>
169+
<phase>verify</phase>
170+
<goals>
171+
<goal>sign</goal>
172+
</goals>
173+
</execution>
174+
</executions>
175+
<configuration>
176+
<gpgArguments>
177+
<arg>--pinentry-mode</arg>
178+
<arg>loopback</arg>
179+
</gpgArguments>
180+
</configuration>
181+
</plugin>
182+
<plugin>
183+
<groupId>org.sonatype.plugins</groupId>
184+
<artifactId>nexus-staging-maven-plugin</artifactId>
185+
<version>1.6.13</version>
186+
<extensions>true</extensions>
187+
<configuration>
188+
<serverId>ossrh-s01</serverId>
189+
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
190+
<autoReleaseAfterClose>false</autoReleaseAfterClose>
191+
</configuration>
192+
</plugin>
193+
</plugins>
194+
</build>
195+
</profile>
196+
</profiles>
197+
</project>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package tech.ydb.lock.provider;
2+
3+
import java.time.Duration;
4+
import org.springframework.boot.context.properties.ConfigurationProperties;
5+
6+
/**
7+
* @author Kirill Kurdyukov
8+
*/
9+
@ConfigurationProperties(prefix = "ydb.lock")
10+
public class YdbLockProperties {
11+
12+
public Duration acquireSemaphoreTimeout = Duration.ofSeconds(5);
13+
14+
public void setAcquireSemaphoreTimeout(Duration acquireSemaphoreTimeout) {
15+
this.acquireSemaphoreTimeout = acquireSemaphoreTimeout;
16+
}
17+
18+
public Duration getAcquireSemaphoreTimeout() {
19+
return acquireSemaphoreTimeout;
20+
}
21+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package tech.ydb.lock.provider;
2+
3+
import java.util.Optional;
4+
import net.javacrumbs.shedlock.core.LockConfiguration;
5+
import net.javacrumbs.shedlock.core.LockProvider;
6+
import net.javacrumbs.shedlock.core.SimpleLock;
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
import tech.ydb.coordination.CoordinationClient;
10+
import tech.ydb.coordination.SemaphoreLease;
11+
12+
/**
13+
* @author Kirill Kurdyukov
14+
*/
15+
public class YdbLockProvider implements LockProvider {
16+
private static final Logger logger = LoggerFactory.getLogger(YdbLockProvider.class);
17+
private static final String YDB_LOCK_NODE_NAME = "shared-lock-ydb";
18+
private static final int ATTEMPT_CREATE_NODE = 10;
19+
20+
private final CoordinationClient coordinationClient;
21+
private final YdbLockProperties ydbLockProperties;
22+
23+
public YdbLockProvider(CoordinationClient coordinationClient, YdbLockProperties ydbLockProperties) {
24+
this.coordinationClient = coordinationClient;
25+
this.ydbLockProperties = ydbLockProperties;
26+
}
27+
28+
public void init() {
29+
for (int i = 0; i < ATTEMPT_CREATE_NODE; i++) {
30+
var status = coordinationClient.createNode(YDB_LOCK_NODE_NAME).join();
31+
32+
if (status.isSuccess()) {
33+
return;
34+
}
35+
36+
if (i == ATTEMPT_CREATE_NODE - 1) {
37+
status.expectSuccess("Failed created coordination service node: " + YDB_LOCK_NODE_NAME);
38+
}
39+
}
40+
}
41+
42+
@Override
43+
public Optional<SimpleLock> lock(LockConfiguration lockConfiguration) {
44+
var coordinationSession = coordinationClient.createSession(YDB_LOCK_NODE_NAME);
45+
46+
coordinationSession.connect().join()
47+
.expectSuccess("Failed creating coordination node session");
48+
49+
logger.debug("Created coordination node session");
50+
51+
coordinationSession.createSemaphore(lockConfiguration.getName(), 1).join()
52+
.expectSuccess("Failed creating semaphore[" + lockConfiguration.getName() +
53+
"], coordination node[" + YDB_LOCK_NODE_NAME + "]");
54+
55+
logger.debug("Created semaphore[" + lockConfiguration.getName() + "]");
56+
57+
var semaphoreLease = coordinationSession.acquireSemaphore(lockConfiguration.getName(), 1,
58+
ydbLockProperties.acquireSemaphoreTimeout).join().getValue();
59+
60+
logger.debug("Semaphore acquired");
61+
62+
return Optional.of(new YdbSimpleLock(semaphoreLease));
63+
}
64+
65+
private record YdbSimpleLock(SemaphoreLease semaphoreLease) implements SimpleLock {
66+
@Override
67+
public void unlock() {
68+
semaphoreLease.release().join();
69+
}
70+
}
71+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package tech.ydb.lock.provider;
2+
3+
import java.sql.SQLException;
4+
import javax.sql.DataSource;
5+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
6+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
7+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
8+
import org.springframework.context.annotation.Bean;
9+
import org.springframework.context.annotation.Configuration;
10+
import tech.ydb.coordination.CoordinationClient;
11+
import tech.ydb.jdbc.YdbConnection;
12+
import tech.ydb.jdbc.YdbDriver;
13+
14+
/**
15+
* @author Kirill Kurdyukov
16+
*/
17+
18+
@Configuration
19+
@EnableConfigurationProperties(YdbLockProperties.class)
20+
public class YdbLockProviderConfiguration {
21+
22+
@Configuration
23+
@ConditionalOnClass(YdbDriver.class)
24+
public static class YdbLockProviderDataSourceConfiguration {
25+
26+
@Bean
27+
@ConditionalOnBean(DataSource.class)
28+
public CoordinationClient coordinationClient(DataSource dataSource) throws SQLException {
29+
try (var ydbConnection = dataSource.getConnection().unwrap(YdbConnection.class)) {
30+
31+
return CoordinationClient.newClient(ydbConnection.getCtx().getGrpcTransport());
32+
}
33+
}
34+
}
35+
36+
@Bean
37+
public YdbLockProvider ydbLockProvider(CoordinationClient coordinationClient,
38+
YdbLockProperties ydbLockProperties) {
39+
var ydbLockProvider = new YdbLockProvider(coordinationClient, ydbLockProperties);
40+
41+
ydbLockProvider.init();
42+
43+
return ydbLockProvider;
44+
}
45+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* @author Kirill Kurdyukov
3+
*/
4+
@NonNullApi
5+
package tech.ydb.lock.provider;
6+
7+
import org.springframework.lang.NonNullApi;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.springframework.boot.autoconfigure.EnableAutoConfiguration=tech.ydb.lock.provider.YdbLockProviderConfiguration
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package tech.ydb.lock.provider;
2+
3+
import org.springframework.boot.test.context.SpringBootTest;
4+
5+
/**
6+
* @author Kirill Kurdyukov
7+
*/
8+
@SpringBootTest
9+
public class TestApp {
10+
}

0 commit comments

Comments
 (0)