Versions
If you are using JDK >17 and up-to-date libraries like Spring 6, use version 5.1.0 (Release Notes). If you are on older JDK or library, use version 4.44.0 (documentation).
Components
Shedlock consists of three parts
- Core - The locking mechanism
- Integration - integration with your application, using Spring AOP, Micronaut AOP or manual code
- Lock provider - provides the lock using an external process like SQL database, Mongo, Redis and others
Enable and configure Scheduled locking (Spring)
First of all, we have to import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>5.13.0</version>
</dependency>
Now we need to integrate the library with Spring. In order to enable schedule locking use @EnableSchedulerLock
annotation
@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "10m")
class MySpringConfiguration {
...
}
Example
Let’s say you have a task which you execute every 15 minutes and which usually takes few minutes to run. Moreover, you want to execute it at most once per 15 minutes. In that case, you can configure it like this:
import net.javacrumbs.shedlock.core.SchedulerLock;
@Scheduled(cron = "0 */15 * * * *")
@SchedulerLock(name = "scheduledTaskName", lockAtMostFor = "14m", lockAtLeastFor = "14m")
public void scheduledTask() {
// do something
}
By setting lockAtMostFor
we make sure that the lock is released even if the node dies. By setting lockAtLeastFor
we make sure it’s not executed more than once in fifteen minutes.
Please note that lockAtMostFor
is just a safety net in case that the node executing the task dies, so set it to
a time that is significantly larger than maximum estimated execution time. If the task takes longer than lockAtMostFor
,
it may be executed again and the results will be unpredictable (more processes will hold the lock).
Configure LockProvider
There are several implementations of LockProvider.
JdbcTemplate
First, create lock table (please note that name
has to be primary key)
# MySQL, MariaDB
CREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until TIMESTAMP(3) NOT NULL,
locked_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));
# Postgres
CREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until TIMESTAMP NOT NULL,
locked_at TIMESTAMP NOT NULL, locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));
# Oracle
CREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until TIMESTAMP(3) NOT NULL,
locked_at TIMESTAMP(3) NOT NULL, locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));
# MS SQL
CREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until datetime2 NOT NULL,
locked_at datetime2 NOT NULL, locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));
# DB2
CREATE TABLE shedlock(name VARCHAR(64) NOT NULL PRIMARY KEY, lock_until TIMESTAMP NOT NULL,
locked_at TIMESTAMP NOT NULL, locked_by VARCHAR(255) NOT NULL);
Or use this liquibase change-set.
Add dependency
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
...
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(
JdbcTemplateLockProvider.Configuration.builder()
.withJdbcTemplate(new JdbcTemplate(dataSource))
.usingDbTime() // Works on Postgres, MySQL, MariaDb, MS SQL, Oracle, DB2, HSQL and H2
.build()
);
}
By specifying usingDbTime()
the lock provider will use UTC time based on the DB server clock.
If you do not specify this option, clock from the app server will be used (the clocks on app servers may not be
synchronized thus leading to various locking issues).
It’s strongly recommended to use usingDbTime()
option as it uses DB engine specific SQL that prevents INSERT conflicts.
See more details here.
For more fine-grained configuration use other options of the Configuration
object
new JdbcTemplateLockProvider(builder()
.withTableName("shdlck")
.withColumnNames(new ColumnNames("n", "lck_untl", "lckd_at", "lckd_by"))
.withJdbcTemplate(new JdbcTemplate(getDatasource()))
.withLockedByValue("my-value")
.withDbUpperCase(true)
.build())
If you need to specify a schema, you can set it in the table name using the usual dot notation
new JdbcTemplateLockProvider(datasource, "my_schema.shedlock")
To use a database with case-sensitive table and column names, the .withDbUpperCase(true)
flag can be used.
Default is false
(lowercase).
Warning
Do not manually delete lock row from the DB table. ShedLock has an in-memory cache of existing lock rows so the row will NOT be automatically recreated until application restart. If you need to, you can edit the row/document, risking only that multiple locks will be held.
Mongo
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-mongo</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.provider.mongo.MongoLockProvider;
...
@Bean
public LockProvider lockProvider(MongoClient mongo) {
return new MongoLockProvider(mongo.getDatabase(databaseName))
}
Please note that MongoDB integration requires Mongo >= 2.4 and mongo-java-driver >= 3.7.0
Reactive Mongo
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-mongo-reactivestreams</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.provider.mongo.reactivestreams.ReactiveStreamsMongoLockProvider;
...
@Bean
public LockProvider lockProvider(MongoClient mongo) {
return new ReactiveStreamsMongoLockProvider(mongo.getDatabase(databaseName))
}
Please note that MongoDB integration requires Mongo >= 4.x and mongodb-driver-reactivestreams 1.x
DynamoDB 2
Depends on AWS SDK v2.
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-dynamodb2</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.provider.dynamodb2.DynamoDBLockProvider;
...
@Bean
public LockProvider lockProvider(software.amazon.awssdk.services.dynamodb.DynamoDbClient dynamoDB) {
return new DynamoDBLockProvider(dynamoDB, "Shedlock");
}
Please note that the lock table must be created externally with
_id
as a partition key.DynamoDBUtils#createLockTable
may be used for creating it programmatically. A table definition is available fromDynamoDBLockProvider
’s Javadoc.
ZooKeeper (using Curator)
Import
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-zookeeper-curator</artifactId>
<version>5.13.0</version>
</dependency>
and configure
import net.javacrumbs.shedlock.provider.zookeeper.curator.ZookeeperCuratorLockProvider;
...
@Bean
public LockProvider lockProvider(org.apache.curator.framework.CuratorFramework client) {
return new ZookeeperCuratorLockProvider(client);
}
By default, nodes for locks will be created under /shedlock
node.
Redis (using Spring RedisConnectionFactory)
Import
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-redis-spring</artifactId>
<version>5.13.0</version>
</dependency>
and configure
import net.javacrumbs.shedlock.provider.redis.spring.RedisLockProvider;
import org.springframework.data.redis.connection.RedisConnectionFactory;
...
@Bean
public LockProvider lockProvider(RedisConnectionFactory connectionFactory) {
return new RedisLockProvider(connectionFactory, ENV);
}
Redis (using Spring ReactiveRedisConnectionFactory)
Import
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-redis-spring</artifactId>
<version>5.13.0</version>
</dependency>
and configure
import net.javacrumbs.shedlock.provider.redis.spring.ReactiveRedisLockProvider;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
...
@Bean
public LockProvider lockProvider(ReactiveRedisConnectionFactory connectionFactory) {
return new ReactiveRedisLockProvider.Builder(connectionFactory)
.environment(ENV)
.build();
}
Redis lock provider uses classical lock mechanism as described here which may not be reliable in case of Redis master failure.
Redis (using Jedis)
Import
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-redis-jedis4</artifactId>
<version>5.13.0</version>
</dependency>
and configure
import net.javacrumbs.shedlock.provider.redis.jedis.JedisLockProvider;
...
@Bean
public LockProvider lockProvider(JedisPool jedisPool) {
return new JedisLockProvider(jedisPool, ENV);
}
Hazelcast
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-hazelcast4</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.provider.hazelcast4.HazelcastLockProvider;
...
@Bean
public HazelcastLockProvider lockProvider(HazelcastInstance hazelcastInstance) {
return new HazelcastLockProvider(hazelcastInstance);
}
Couchbase
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-couchbase-javaclient3</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.provider.couchbase.javaclient.CouchbaseLockProvider;
...
@Bean
public CouchbaseLockProvider lockProvider(Bucket bucket) {
return new CouchbaseLockProvider(bucket);
}
For Couchbase 3 use shedlock-provider-couchbase-javaclient3
module and net.javacrumbs.shedlock.provider.couchbase3
package.
Elasticsearch
I am really not sure it’s a good idea to use Elasticsearch as a lock provider. But if you have no other choice, you can. Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-elasticsearch8</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import static net.javacrumbs.shedlock.provider.elasticsearch8.ElasticsearchLockProvider;
...
@Bean
public ElasticsearchLockProvider lockProvider(ElasticsearchClient client) {
return new ElasticsearchLockProvider(client);
}
OpenSearch
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-opensearch</artifactId>
<version>4.36.1</version>
</dependency>
Configure:
import static net.javacrumbs.shedlock.provider.opensearch.OpenSearchLockProvider;
...
@Bean
public OpenSearchLockProvider lockProvider(RestHighLevelClient highLevelClient) {
return new OpenSearchLockProvider(highLevelClient);
}
Cassandra
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-cassandra</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.provider.cassandra.CassandraLockProvider;
import net.javacrumbs.shedlock.provider.cassandra.CassandraLockProvider.Configuration;
...
@Bean
public CassandraLockProvider lockProvider(CqlSession cqlSession) {
return new CassandraLockProvider(Configuration.builder().withCqlSession(cqlSession).withTableName("lock").build());
}
Example for creating default keyspace and table in local Cassandra instance:
CREATE KEYSPACE shedlock with replication={'class':'SimpleStrategy', 'replication_factor':1} and durable_writes=true;
CREATE TABLE shedlock.lock (name text PRIMARY KEY, lockUntil timestamp, lockedAt timestamp, lockedBy text);
Please, note that CassandraLockProvider uses Cassandra driver v4, which is part of Spring Boot since 2.3.
Consul
ConsulLockProvider has one limitation: lockAtMostFor setting will have a minimum value of 10 seconds. It is dictated by consul’s session limitations.
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-consul</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.provider.consul.ConsulLockProvider;
...
@Bean // for micronaut please define preDestroy property @Bean(preDestroy="close")
public ConsulLockProvider lockProvider(com.ecwid.consul.v1.ConsulClient consulClient) {
return new ConsulLockProvider(consulClient);
}
Please, note that Consul lock provider uses ecwid consul-api client, which is part of spring cloud consul integration (the spring-cloud-starter-consul-discovery
package).
ArangoDB
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-arangodb</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.provider.arangodb.ArangoLockProvider;
...
@Bean
public ArangoLockProvider lockProvider(final ArangoOperations arangoTemplate) {
return new ArangoLockProvider(arangoTemplate.driver().db(DB_NAME));
}
Please, note that ArangoDB lock provider uses ArangoDB driver v6.7, which is part of arango-spring-data in version 3.3.0.
Neo4j
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-neo4j</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.core.LockConfiguration;
...
@Bean
Neo4jLockProvider lockProvider(org.neo4j.driver.Driver driver) {
return new Neo4jLockProvider(driver);
}
Please make sure that neo4j-java-driver
version used by shedlock-provider-neo4j
matches the driver version used in your
project (if you use spring-boot-starter-data-neo4j
, it is probably provided transitively).
Etcd
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-etcd-jetcd</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.provider.etcd.jetcd.EtcdLockProvider;
...
@Bean
public LockProvider lockProvider(Client client) {
return new EtcdLockProvider(client);
}
Apache Ignite
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-ignite</artifactId>
<version>5.13.0</version>
</dependency>
Configure:
import net.javacrumbs.shedlock.provider.ignite.IgniteLockProvider;
...
@Bean
public LockProvider lockProvider(Ignite ignite) {
return new IgniteLockProvider(ignite);
}
In-Memory
If you want to use a lock provider in tests there is an in-Memory implementation.
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-inmemory</artifactId>
<version>5.13.0</version>
<scope>test</scope>
</dependency>
import net.javacrumbs.shedlock.provider.inmemory.InMemoryLockProvider;
...
@Bean
public LockProvider lockProvider() {
return new InMemoryLockProvider();
}
Datastore
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-datastore</artifactId>
<version>5.13.0</version>
</dependency>
and configure
import net.javacrumbs.shedlock.provider.datastore.DatastoreLockProvider;
...
@Bean
public LockProvider lockProvider(com.google.cloud.datastore.Datastore datastore) {
return new DatastoreLockProvider(datastore);
}
Spanner
Import the project
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-spanner</artifactId>
<version>5.13.0</version>
</dependency>
Configure
import net.javacrumbs.shedlock.provider.spanner.SpannerLockProvider;
...
// Basic
@Bean
public LockProvider lockProvider(DatabaseClient databaseClient) {
return new SpannerLockProvider(databaseClientSupplier);
}
// Custom host, table and column names
@Bean
public LockProvider lockProvider(DatabaseClient databaseClient) {
var config = SpannerLockProvider.Configuration.builder()
.withDatabaseClient(databaseClientSupplier)
.withTableConfiguration(SpannerLockProvider.TableConfiguration.builder()
...
// Custom table and column names
.build())
.withHostName("customHostName")
.build();
return new SpannerLockProvider(config);
}
Multi-tenancy
If you have multi-tenancy use-case you can use a lock provider similar to this one (see the full example)
private static abstract class MultiTenancyLockProvider implements LockProvider {
private final ConcurrentHashMap<String, LockProvider> providers = new ConcurrentHashMap<>();
@Override
public @NonNull Optional<SimpleLock> lock(@NonNull LockConfiguration lockConfiguration) {
String tenantName = getTenantName(lockConfiguration);
return providers.computeIfAbsent(tenantName, this::createLockProvider).lock(lockConfiguration);
}
protected abstract LockProvider createLockProvider(String tenantName) ;
protected abstract String getTenantName(LockConfiguration lockConfiguration);
}
Customization
You can customize the behavior of the library by implementing LockProvider
interface. Let’s say you want to implement
a special behavior after a lock is obtained. You can do it like this:
public class MyLockProvider implements LockProvider {
private final LockProvider delegate;
public MyLockProvider(LockProvider delegate) {
this.delegate = delegate;
}
@Override
public Optional<SimpleLock> lock(LockConfiguration lockConfiguration) {
Optional<SimpleLock> lock = delegate.lock(lockConfiguration);
if (lock.isPresent()) {
// do something
}
return lock;
}
}
Micronaut integration
Since version 4.0.0, it’s possible to use Micronaut framework for integration
Import the project:
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<!-- Micronaut 3 -->
<artifactId>shedlock-micronaut</artifactId>
<!-- For Micronaut 4 use -->
<!-- <artifactId>shedlock-micronaut4</artifactId> -->
<version>5.13.0</version>
</dependency>
Configure default lockAtMostFor value (application.yml):
shedlock:
defaults:
lock-at-most-for: 1m
Configure lock provider:
@Singleton
public LockProvider lockProvider() {
... select and configure your lock provider
}
Configure the scheduled task:
@Scheduled(fixedDelay = "1s")
@SchedulerLock(name = "myTask")
public void myTask() {
assertLocked();
...
}
Locking without a framework
It is possible to use ShedLock without a framework
LockingTaskExecutor executor = new DefaultLockingTaskExecutor(lockProvider);
...
Instant lockAtMostUntil = Instant.now().plusSeconds(600);
executor.executeWithLock(runnable, new LockConfiguration("lockName", lockAtMostUntil));
TaskScheduler proxy
This mode wraps Spring TaskScheduler
in an AOP proxy. This mode does not play well with instrumentation libraries
like opentelementry that also wrap TaskScheduler. Please only use it if you know what you are doing.
It can be switched-on like this (PROXY_SCHEDULER was the default method before 4.0.0):
@EnableSchedulerLock(interceptMode = PROXY_SCHEDULER)
If you do not specify your task scheduler, a default one is created for you. If you have special needs, just create a bean implementing TaskScheduler
interface and it will get wrapped into the AOP proxy automatically.
@Bean
public TaskScheduler taskScheduler() {
return new MySpecialTaskScheduler();
}
Alternatively, you can define a bean of type ScheduledExecutorService
and it will automatically get used by the tasks
scheduling mechanism.
Lock assert
To prevent misconfiguration errors, like AOP misconfiguration, missing annotation etc., you can assert that the lock works by using LockAssert:
@Scheduled(...)
@SchedulerLock(..)
public void scheduledTask() {
// To assert that the lock is held (prevents misconfiguration errors)
LockAssert.assertLocked();
// do something
}
In unit tests you can switch-off the assertion by calling LockAssert.TestHelper.makeAllAssertsPass(true)
on given thread (as in this example).
Kotlin gotchas
The library is tested with Kotlin and works fine. The only issue is Spring AOP which does not work on final method. If you use @SchedulerLock
with @Component
annotation, everything should work since Kotlin Spring compiler plugin will automatically ‘open’ the method for you. If @Component
annotation is not present, you
have to open the method by yourself. (see this issue for more details)
Caveats
Locks in ShedLock have an expiration time which leads to the following possible issues.
- If the task runs longer than
lockAtMostFor
, the task can be executed more than once - If the clock difference between two nodes is more than
lockAtLeastFor
or minimal execution time the task can be executed more than once.
Troubleshooting
Help, ShedLock does not do what it’s supposed to do!
- Upgrade to the newest version
- Use LockAssert to ensure that AOP is correctly configured.
- If it does not work, please read about Spring AOP internals (for example here)
- Check the storage. If you are using JDBC, check the ShedLock table. If it’s empty, ShedLock is not properly configured. If there is more than one record with the same name, you are missing a primary key.
- Use ShedLock debug log. ShedLock logs interesting information on DEBUG level with logger name
net.javacrumbs.shedlock
. It should help you to see what’s going on. - For short-running tasks consider using
lockAtLeastFor
. If the tasks are short-running, they could be executed one after another,lockAtLeastFor
can prevent it.
Release notes
5.13.0 (2024-04-05)
- #1779 Ability to rethrow unexpected exception in JdbcTemplateStorageAccessor
- Dependency updates
5.12.0 (2024-02-29)
- #1800 Enable lower case for database type when using usingDbTime()
- #1804 Startup error with Neo4j 5.17.0
- Dependency updates
4.47.0 (2024-03-01)
- #1800 Enable lower case for database type when using usingDbTime() (thanks @yuagu1)
5.11.0 (2024-02-13)
- #1753 Fix SpEL for methods with parameters
- Dependency updates
5.10.2 (2023-12-07)
- #1635 fix makeAllAssertsPass locks only once
- Dependency updates
5.10.1 (2023-12-06)
- #1635 fix makeAllAssertsPass(false) throws NoSuchElementException
- Dependency updates
5.10.0 (2023-11-07)
- SpannerLockProvider added (thanks @pXius)
- Dependency updates
5.6.0
- Ability to explicitly set database product in JdbTemplateLockProvider (thanks @metron2)
- Removed forgotten versions from BOM
- Dependency updates
5.4.0 (2023-06-06)
- Handle uncategorized SQL exceptions (thanks @jaam)
- Dependency updates
5.2.0 (2023-03-06)
- Uppercase in JdbcTemplateProvider (thanks @Ragin-LundF)
- Dependency updates
5.0.1 (2022-12-10)
- Work around broken Spring 6 exception translation https://github.com/lukas-krecan/ShedLock/issues/1272
4.44.0 (2022-12-29)
- Insert ignore for MySQL https://github.com/lukas-krecan/ShedLock/commit/8a4ae7ad8103bb47f55d43bccf043ca261c24d7a
4.43.0 (2022-12-04)
- Better logging in JdbcTemplateProvider
- Dependency updates
4.42.0 (2022-09-16)
- Deprecate old Couchbase lock provider
- Dependency updates
4.40.0 (2022-08-11)
- Fixed caching issues when the app is started by the DB does not exist yet (#1129)
- Dependency updates
4.39.0 (2022-07-26)
- Introduced elasticsearch8 LockProvider and deperecated the orignal one (thanks @MarAra)
- Dependency updates
4.38.0 (2022-07-02)
- ReactiveRedisLockProvider added (thanks @ericwcc)
- Dependency updates
4.37.0 (2022-06-14)
- OpenSearch provider (thanks @Pinny3)
- Fix wrong reference to reactive Mongo in BOM #1048
- Dependency updates
4.36.0 (2022-05-28)
- shedlock-bom module added
- Dependency updates
4.35.0 (2022-05-16)
- Neo4j allows to specify database thanks @SergeyPlatonov
- Dependency updates
4.33.0
- memcached provider added (thanks @pinkhello)
- Dependency updates
4.32.0
- JDBC provider does not change autocommit attribute
- Dependency updates
4.31.0
- Jedis 4 lock provider
- Dependency updates
4.30.0
- In-memory lock provider added (thanks @kkocel)
- Dependency updates
4.28.0
- Neo4j lock provider added (thanks @thimmwork)
- Library upgrades
4.27.0
- Ability to set transaction isolation in JdbcTemplateLockProvider
- Library upgrades
4.26.0
- KeepAliveLockProvider introduced
- Library upgrades
4.25.0
- LockExtender added
4.23.0
- Ability to set serialConsistencyLevel in Cassandra (thanks @DebajitKumarPhukan)
- Introduced shedlock-provider-jdbc-micronaut module (thanks @drmaas)
4.22.1
- Catching and logging Cassandra exception
4.21.0
- Elastic unlock using IMMEDIATE refresh policy #422
- DB2 JDBC lock provider uses microseconds in DB time
- Various library upgrades
4.20.1
- Fixed DB JDBC server time #378
4.19.1
- Fixed devtools compatibility #368
4.16.0
- Spring - EnableSchedulerLock.order param added to specify AOP proxy order
- JDBC - Log unexpected exceptions at ERROR level
- Hazelcast upgraded to 4.1
4.15.1
- Fix session leak in Consul provider #340 (thanks @haraldpusch)
4.15.0
- ArangoDB lock provider added (thanks @patrick-birkle)
4.12.0
- Lazy initialization of SqlStatementsSource #258
4.11.1
- MongoLockProvider uses mongodb-driver-sync
- Removed deprecated constructors from MongoLockProvider
4.10.1
- New Mongo reactive streams driver (thanks @codependent)
4.9.3
- Fixed JdbcTemplateLockProvider useDbTime() locking #244 thanks @gjorgievskivlatko
4.9.2
- Do not fail on DB type determining code if DB connection is not available
4.8.0
- DynamoDB 2 module introduced (thanks Mark Egan)
- JDBC template code refactored to not log error on failed insert in Postgres
- INSERT .. ON CONFLICT UPDATE is used for Postgres
4.7.1
- Make LockAssert.TestHelper public
4.7.0
- New module for Hazelcasts 4
- Ability to switch-off LockAssert in unit tests
4.5.2
- Made compatible with PostgreSQL JDBC Driver 42.2.11
4.5.1
- Inject redis template
4.5.0
- ClockProvider introduced
- MongoLockProvider(MongoDatabase) introduced
4.3.1
- Introduced shedlock-provider-redis-spring-1 to make it work around Spring Data Redis 1 issue #105 (thanks @rygh4775)
4.2.0
- Cassandra provider (thanks @mitjag)
4.1.0
- More configuration option for JdbcTemplateProvider
4.0.4
- Allow configuration of key prefix in RedisLockProvider #181 (thanks @krm1312)
4.0.3
- Fixed junit dependency scope #179
4.0.2
Fix NPE caused by Redisson #178
4.0.1
DefaultLockingTaskExecutor made reentrant #175
3.0.1
Fixed bean definition configuration #171
2.4.0
- Fixed potential deadlock in Hazelcast (thanks @HubertTatar)
- Finding class level annotation in proxy method mode (thanks @volkovs)
- ScheduledLockConfigurationBuilder deprecated
2.3.0
- LockProvides is initialized lazilly so it does not change DataSource initialization order
2.2.1
- MongoLockProvider accepts MongoCollection as a constructor param
2.2.0
- DynamoDBLockProvider added
2.1.0
- MongoLockProvider rewritten to use upsert
- ElasticsearchLockProvider added
1.3.0
- Can set Timezone to JdbcTemplateLock provider
1.1.1
- Spring RedisLockProvider refactored to use RedisTemplate
1.0.0
- Upgraded dependencies to Spring 5 and Spring Data 2
- Removed deprecated net.javacrumbs.shedlock.provider.jedis.JedisLockProvider (use net.javacrumbs.shedlock.provider.redis.jedis.JedisLockProvide instead)
- Removed deprecated SpringLockableTaskSchedulerFactory (use ScheduledLockConfigurationBuilder instead)
0.18.2
- ablility to clean lock cache
0.18.1
- shedlock-provider-redis-spring made compatible with spring-data-redis 1.x.x
0.18.0
- Added shedlock-provider-redis-spring (thanks to @siposr)
- shedlock-provider-jedis moved to shedlock-provider-redis-jedis
0.16.1
- Automatically closing TaskExecutor on Spring shutdown
0.16.0
- Removed spring-test from shedlock-spring compile time dependencies
- Added Automatic-Module-Names
0.15.1
- Hazelcast works with remote cluster
0.15.0
- Fixed ScheduledLockConfigurationBuilder interfaces #32
- Hazelcast code refactoring
0.13.0
- Jedis constructor made more generic (thanks to @mgrzeszczak)
0.10.0
- jdbc-template-provider does not participate in task transaction
0.8.0
- LockableTaskScheduler made AutoClosable so it’s closed upon Spring shutdown
0.6.0
- Possible to configure defaultLockFor time so it does not have to be repeated in every annotation
0.5.0
- ZooKeeper nodes created under /shedlock by default
0.4.1
- JdbcLockProvider insert does not fail on DataIntegrityViolationException
0.4.0
- Extracted LockingTaskExecutor
- LockManager.executeIfNotLocked renamed to executeWithLock
- Default table name in JDBC lock providers
0.3.0
@ShedlulerLock.name
made obligatory@ShedlulerLock.lockForMillis
renamed to lockAtMostFor- Adding plain JDBC LockProvider
- Adding ZooKeepr LockProvider