Natureknight/SimpleLock

★ 1Forks 0JavaGitHub ↗Compare

README

measure?project=Natureknight SimpleLock&metric=alert status measure?project=Natureknight SimpleLock&metric=coverage measure?project=Natureknight SimpleLock&metric=bugs measure?project=Natureknight SimpleLock&metric=vulnerabilities
Java JitPack Spring Boot License

SimpleLock for Spring Boot: (SQL and NoSQL)

Distributed lock ensures your method cannot be run in parallel from multiple JVMs (cluster of servers, microservices, …​). It uses a common store to keep track of used locks and your method needs to acquire lock to run.

By default, locks follow methods lifecycle. They are obtained at the start of the method and released at the end of the method. Manual controlling is supported and explained later in this document.

All locks acquired by SimpleLock implementations in this project will expire after 10 seconds by default. These options are customizable.

Manually controlled locks:

Use the releaseAfter attribute to control the duration of holding the lock (default is 10 seconds)
Note this flag will override the releaseAfter if set altogether

Example

Check the simplelock-example module for more context.

Using @SimpleJdbcLocked annotation:

@Component
public class MyJdbcLockedService {

    /**
     * Invoke with distributed JDBC lock, by holding the lock.
     */
    @SimpleJdbcLocked
    public void doSomething() {
        // locked method body
    }

    /**
     * Invoke with distributed JDBC lock, by releasing the lock immediately.
     */
    @SimpleJdbcLocked(releaseStrategy = ReleaseStrategy.WITHOUT_DELAY)
    public void doSomethingElse() {
        // locked method body
    }
}

or programmatically, where you’re allowed to propagate the lock token further into your service and release the lock whenever suitable for your use case, e.g. by sending the token in an event payload and release the lock after the event has been received back from the message broker:

@Component
@RequiredArgsConstructor
@Slf4j
public class MyJdbcLockedService {

    private final SimpleLock simpleLock;

    public void doSomething(UUID id) {
        simpleLock.acquire(id.toString())
                // IMPORTANT: lock has been acquired successfully only if the token is present,
                // so make sure you have this check wrapping your service logic that needs to be locked
                .ifPresent(token -> {
                    log.info("Some action executed concurrently for id={}", id);
                    simpleLock.release(token);
                });
    }
}

Unsuccessful locks:

If method cannot be locked, the execution will be skipped.

Method might not acquire the lock if:

  1. Another method/thread/service node acquired the lock

  2. Lock implementation threw an exception

Enabling locking

Project provides the following out-of-the-box SimpleLock implementations:

  • SQL (see JdbcSimpleLock)

  • NoSQL (see MongoSimpleLock)

Supported SQL databases:

List of supported databases:

  • MySQL

  • MariaDB

  • PostgreSQL

  • Oracle

  • H2

Supported NoSQL databases:

List of supported NoSQL databases:

  • MongoDB

Configuration properties: (SQL)

Property Description Default

simplelock.jdbc.enabled

Whether the JDBC lock is enabled

true

simplelock.jdbc.expiry.enabled

Whether the lock expiry is enabled

true

simplelock.jdbc.expiry.release-strategy

Whether the release strategy is with_delay or without_delay

without_delay

simplelock.jdbc.expiry.min-delay

Expiry delay

1

simplelock.jdbc.expiry.time-unit

Time unit of the expiry delay

days

Annotation

@SimpleJdbcLocked

Configuration properties: (NoSQL)

Property Description Default

simplelock.mongo.enabled

Whether the MongoDB lock is enabled

true

simplelock.mongo.expiry.enabled

Whether the lock expiry is enabled

true

simplelock.mongo.expiry.release-strategy

Whether the release strategy is with_delay or without_delay

without_delay

simplelock.mongo.expiry.min-delay

Expiry delay

1

simplelock.mongo.expiry.time-unit

Time unit of the expiry delay

days

Annotation

@SimpleMongoLocked

Importing into your project:

Maven

Add the jitpack repository into your pom.xml:

<repositories>
  <repository>
    <id>jitpack.io</id>
    <url>https://jitpack.io</url>
  </repository>
</repositories>

Use the BOM com.github.natureknight.simplelock:simplelock-dependencies:3.1.2 or add the project dependency into your pom.xml for SQL:

<dependencies>
  <dependency>
    <groupId>com.github.natureknight.simplelock</groupId>
    <artifactId>simplelock-spring-starter-jdbc</artifactId>
    <version>3.1.2</version>
  </dependency>
</dependencies>

Or add the project dependency into your pom.xml for NoSQL:

<dependencies>
  <dependency>
    <groupId>com.github.natureknight.simplelock</groupId>
    <artifactId>simplelock-spring-starter-mongo</artifactId>
    <version>3.1.2</version>
  </dependency>
</dependencies>

Gradle

Add the jitpack repository into your build.gradle:

repositories {
    maven {
        url = 'https://jitpack.io'
    }
}

Add the project dependency into your build.gradle based on your needs (choose either SQL or NoSQL):

depedencyManagement {
    imports {
        mavenBom 'com.github.natureknight.simplelock:simplelock-dependencies:3.1.2'
    }
}

dependencies {
    implementation('com.github.natureknight.simplelock:simplelock-spring-starter-jdbc')
    // or
    implementation('com.github.natureknight.simplelock:simplelock-spring-starter-mongo')

Or add the project dependency into your build.gradle without using the BOM:

implementation('com.github.natureknight.simplelock:simplelock-spring-starter-jdbc:3.1.2')
// or
implementation('com.github.natureknight.simplelock:simplelock-spring-starter-mongo:3.1.2')

Compatibility:

Version Spring Boot version

1.+

2.+

2.+

2.+

Customization:

If you want to use custom lock implementations, simply implement com.simplelock.api.SimpleLock interface and register it in a configuration.

Changelog:

3.0.3

  • Fixed MongoDB index creation

3.0.2

  • Simplify project’s logic

  • Fixed minor issue related to MongoDB index creating

  • Cleanup

2.1.0

  • Added support for MongoDB

2.0.3

  • Refactoring and optimized project structure

1.6.1

  • Added simplelock-example module.

1.6.0

  • Replaced acquireLockForMethod by acquireLockWithKeyPrefix

  • Updated README

1.5.9

  • Fixed reported Sonar issues

1.5.8

  • Added SonarCloud analysis

  • Remove vulnerable transitive dependency

1.5.5 - 1.5.7

  • Update tests

1.5.4

  • Added list of supported databases and tests

1.5.3

  • Increase test coverage

1.5.2

  • Added tests for simplelock-spring-starter-jdbc module

1.5.1

  • Renamed few leftovers for simplelock-spring-starter-jdbc

1.5.0

  • Renamed module simplelock-jdbc to simplelock-spring-starter-jdbc

1.4.1

  • Update project structure

  • Update README

1.4.0

  • By default, hold the lock for 10 seconds

  • Update dependency tree

  • Update project structure

1.3.1

  • Fixed an issue with functionality for appending the invoking method prefix

1.3.0

  • Added functionality to lock for same lock key but different invocation points

1.2.7

  • Update configuration properties by removing com.github prefix

1.2.2 - 1.2.6

  • Improved logging

1.2.1

  • Fixed an issue with transitive dependency for SLF4J

1.2.0

  • Added configuration properties

  • Update README

1.1.7

  • Release lock synchronously in case releaseAfter is set to 0

  • Improved logging

1.1.6

  • Version bump

1.1.5

  • Fixed transitive dependency for SLF4J

1.1.4

  • Fixed an issue with DuplicateKeyException swallow due to previous commit

1.1.3

  • Skip execution if lock could not be acquired

1.1.2

  • Allow clients to choose the TimeUnit when holding the lock

1.1.1

  • Swallow JDBC exception in case lock could not be acquired

1.1.0

  • Release version

Contributors

Natureknight

Issues