{"id":13458642,"url":"https://github.com/lukas-krecan/ShedLock","last_synced_at":"2025-03-24T15:31:47.366Z","repository":{"id":37431516,"uuid":"76177416","full_name":"lukas-krecan/ShedLock","owner":"lukas-krecan","description":"Distributed lock for your scheduled tasks","archived":false,"fork":false,"pushed_at":"2025-03-17T18:08:28.000Z","size":7826,"stargazers_count":3798,"open_issues_count":32,"forks_count":535,"subscribers_count":70,"default_branch":"master","last_synced_at":"2025-03-18T15:05:29.805Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lukas-krecan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-12-11T13:53:59.000Z","updated_at":"2025-03-18T02:01:05.000Z","dependencies_parsed_at":"2023-02-14T18:30:46.996Z","dependency_job_id":"ab239f38-de53-4d98-ad97-47a1f78add8f","html_url":"https://github.com/lukas-krecan/ShedLock","commit_stats":{"total_commits":2818,"total_committers":82,"mean_commits":34.36585365853659,"dds":0.5461320085166785,"last_synced_commit":"e8e1714b054cbce8e8b170d78aa59bf225e9b89e"},"previous_names":[],"tags_count":133,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukas-krecan%2FShedLock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukas-krecan%2FShedLock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukas-krecan%2FShedLock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukas-krecan%2FShedLock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lukas-krecan","download_url":"https://codeload.github.com/lukas-krecan/ShedLock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245298120,"owners_count":20592542,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T09:00:54.804Z","updated_at":"2025-03-24T15:31:42.356Z","avatar_url":"https://github.com/lukas-krecan.png","language":"Java","readme":"ShedLock\n========\n[![Apache License 2](https://img.shields.io/badge/license-ASF2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.txt) [![Build Status](https://github.com/lukas-krecan/ShedLock/workflows/CI/badge.svg)](https://github.com/lukas-krecan/ShedLock/actions) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/net.javacrumbs.shedlock/shedlock-parent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/net.javacrumbs.shedlock/shedlock-parent)\n\nShedLock makes sure that your scheduled tasks are executed at most once at the same time.\nIf a task is being executed on one node, it acquires a lock which prevents execution of the same task from another node (or thread).\nPlease note, that **if one task is already being executed on one node, execution on other nodes does not wait, it is simply skipped**.\n\nShedLock uses an external store like Mongo, JDBC database, Redis, Hazelcast, ZooKeeper or others for coordination.\n\nFeedback and pull-requests welcome!\n\n#### ShedLock is not a distributed scheduler\nPlease note that ShedLock is not and will never be full-fledged scheduler, it's just a lock. If you need a distributed\nscheduler, please use another project ([db-scheduler](https://github.com/kagkarlsson/db-scheduler), [JobRunr](https://www.jobrunr.io/en/)).\nShedLock is designed to be used in situations where you have scheduled tasks that are not ready to be executed in parallel, but can be safely\nexecuted repeatedly. Moreover, the locks are time-based and ShedLock assumes that clocks on the nodes are synchronized.\n\n+ [Versions](#versions)\n+ [Components](#components)\n+ [Usage](#usage)\n+ [Lock Providers](#configure-lockprovider)\n  - [JdbcTemplate](#jdbctemplate)\n  - [R2DBC](#r2dbc)\n  - [jOOQ](#jooq-lock-provider)\n  - [Micronaut Data Jdbc](#micronaut-data-jdbc)\n  - [Mongo](#mongo)\n  - [DynamoDB](#dynamodb)\n  - [DynamoDB 2](#dynamodb-2)\n  - [ZooKeeper (using Curator)](#zookeeper-using-curator)\n  - [Redis (using Spring RedisConnectionFactory)](#redis-using-spring-redisconnectionfactory)\n  - [Redis (using Spring ReactiveRedisConnectionFactory)](#redis-using-spring-reactiveredisconnectionfactory)\n  - [Redis (using Jedis)](#redis-using-jedis)\n  - [Hazelcast](#hazelcast)\n  - [Couchbase](#couchbase)\n  - [ElasticSearch](#elasticsearch)\n  - [OpenSearch](#opensearch)\n  - [CosmosDB](#cosmosdb)\n  - [Cassandra](#cassandra)\n  - [Consul](#consul)\n  - [ArangoDB](#arangodb)\n  - [Neo4j](#neo4j)\n  - [Etcd](#etcd)\n  - [Apache Ignite](#apache-ignite)\n  - [In-Memory](#in-memory)\n  - [Memcached](#memcached-using-spymemcached)\n  - [Datastore](#datastore)\n+ [Multi-tenancy](#multi-tenancy)\n+ [Customization](#customization)\n+ [Duration specification](#duration-specification)\n+ [Extending the lock](#extending-the-lock)\n+ [Micronaut integration](#micronaut-integration)\n+ [CDI integration](#cdi-integration)\n+ [Locking without a framework](#locking-without-a-framework)\n+ [Troubleshooting](#troubleshooting)\n+ [Modes of Spring integration](#modes-of-spring-integration)\n  - [Scheduled method proxy](#scheduled-method-proxy)\n  - [TaskScheduler proxy](#taskscheduler-proxy)\n+ [Release notes](#release-notes)\n\n## Versions\nIf you are using JDK \u003e17 and up-to-date libraries like Spring 6, use version **5.1.0** ([Release Notes](#500-2022-12-10)). If you\nare on older JDK or library, use version **4.44.0** ([documentation](https://github.com/lukas-krecan/ShedLock/tree/version4)).\n\n## Components\nShedlock consists of three parts\n* Core - The locking mechanism\n* Integration - integration with your application, using Spring AOP, Micronaut AOP or manual code\n* Lock provider - provides the lock using an external process like SQL database, Mongo, Redis and others\n\n## Usage\nTo use ShedLock, you do the following\n1) Enable and configure Scheduled locking\n2) Annotate your scheduled tasks\n3) Configure a Lock Provider\n\n\n### Enable and configure Scheduled locking (Spring)\nFirst of all, we have to import the project\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-spring\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nNow we need to integrate the library with Spring. In order to enable schedule locking use `@EnableSchedulerLock` annotation\n\n```java\n@Configuration\n@EnableScheduling\n@EnableSchedulerLock(defaultLockAtMostFor = \"10m\")\nclass MySpringConfiguration {\n    ...\n}\n```\n\n### Annotate your scheduled tasks\n\n```java\nimport net.javacrumbs.shedlock.spring.annotation.SchedulerLock;\n\n...\n\n@Scheduled(...)\n@SchedulerLock(name = \"scheduledTaskName\")\npublic void scheduledTask() {\n    // To assert that the lock is held (prevents misconfiguration errors)\n    LockAssert.assertLocked();\n    // do something\n}\n```\n\nThe `@SchedulerLock` annotation has several purposes. First of all, only annotated methods are locked, the library ignores\nall other scheduled tasks. You also have to specify the name for the lock. Only one task with the same name can be executed\nat the same time.\n\nYou can also set `lockAtMostFor` attribute which specifies how long the lock should be kept in case the\nexecuting node dies. This is just a fallback, under normal circumstances the lock is released as soon the tasks finishes\n(unless `lockAtLeastFor` is specified, see below)\n**You have to set `lockAtMostFor` to a value which is much longer than normal execution time.** If the task takes longer than\n`lockAtMostFor` the resulting behavior may be unpredictable (more than one process will effectively hold the lock).\n\nIf you do not specify `lockAtMostFor` in `@SchedulerLock` default value from `@EnableSchedulerLock` will be used.\n\nLastly, you can set `lockAtLeastFor` attribute which specifies minimum amount of time for which the lock should be kept.\nIts main purpose is to prevent execution from multiple nodes in case of really short tasks and clock difference between the nodes.\n\nAll the annotations support Spring Expression Language (SpEL).\n\n#### Example\nLet's say you have a task which you execute every 15 minutes and which usually takes few minutes to run.\nMoreover, you want to execute it at most once per 15 minutes. In that case, you can configure it like this:\n\n```java\nimport net.javacrumbs.shedlock.core.SchedulerLock;\n\n\n@Scheduled(cron = \"0 */15 * * * *\")\n@SchedulerLock(name = \"scheduledTaskName\", lockAtMostFor = \"14m\", lockAtLeastFor = \"14m\")\npublic void scheduledTask() {\n    // do something\n}\n\n```\nBy setting `lockAtMostFor` we make sure that the lock is released even if the node dies. By setting `lockAtLeastFor`\nwe make sure it's not executed more than once in fifteen minutes.\nPlease note that **`lockAtMostFor` is just a safety net in case that the node executing the task dies, so set it to\na time that is significantly larger than maximum estimated execution time.**  If the task takes longer than `lockAtMostFor`,\nit may be executed again and the results will be unpredictable (more processes will hold the lock).\n\n### Configure LockProvider\nThere are several implementations of LockProvider.\n\n#### JdbcTemplate\nFirst, create lock table (**please note that `name` has to be primary key**)\n\n```sql\n# MySQL, MariaDB\nCREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until TIMESTAMP(3) NOT NULL,\n    locked_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));\n\n# Postgres\nCREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until TIMESTAMP NOT NULL,\n    locked_at TIMESTAMP NOT NULL, locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));\n\n# Oracle\nCREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until TIMESTAMP(3) NOT NULL,\n    locked_at TIMESTAMP(3) NOT NULL, locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));\n\n# MS SQL\nCREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until datetime2 NOT NULL,\n    locked_at datetime2 NOT NULL, locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));\n\n# DB2\nCREATE TABLE shedlock(name VARCHAR(64) NOT NULL PRIMARY KEY, lock_until TIMESTAMP NOT NULL,\n    locked_at TIMESTAMP NOT NULL, locked_by VARCHAR(255) NOT NULL);\n```\n\nOr use [this](micronaut/test/micronaut-jdbc/src/main/resources/db/liquibase-changelog.xml) liquibase change-set.\n\nAdd dependency\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-jdbc-template\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;\n\n...\n@Bean\npublic LockProvider lockProvider(DataSource dataSource) {\n            return new JdbcTemplateLockProvider(\n                JdbcTemplateLockProvider.Configuration.builder()\n                .withJdbcTemplate(new JdbcTemplate(dataSource))\n                .usingDbTime() // Works on Postgres, MySQL, MariaDb, MS SQL, Oracle, DB2, HSQL and H2\n                .build()\n            );\n}\n```\nBy specifying `usingDbTime()` the lock provider will use UTC time based on the DB server clock.\nIf you do not specify this option, clock from the app server will be used (the clocks on app servers may not be\nsynchronized thus leading to various locking issues).\n\nIt's strongly recommended to use `usingDbTime()` option as it uses DB engine specific SQL that prevents INSERT conflicts.\nSee more details [here](https://stackoverflow.com/a/76774461/277042).\n\nFor more fine-grained configuration use other options of the `Configuration` object\n\n```java\nnew JdbcTemplateLockProvider(builder()\n    .withTableName(\"shdlck\")\n    .withColumnNames(new ColumnNames(\"n\", \"lck_untl\", \"lckd_at\", \"lckd_by\"))\n    .withJdbcTemplate(new JdbcTemplate(getDatasource()))\n    .withLockedByValue(\"my-value\")\n    .withDbUpperCase(true)\n    .build())\n```\n\nIf you need to specify a schema, you can set it in the table name using the usual dot notation\n`new JdbcTemplateLockProvider(datasource, \"my_schema.shedlock\")`\n\nTo use a database with case-sensitive table and column names, the `.withDbUpperCase(true)` flag can be used.\nDefault is `false` (lowercase).\n\n\n#### Warning\n**Do not manually delete lock row from the DB table.** ShedLock has an in-memory cache of existing lock rows\nso the row will NOT be automatically recreated until application restart. If you need to, you can edit the row/document, risking only\nthat multiple locks will be held.\n\n#### R2DBC\nIf you are really brave, you can try experimental R2DBC support. Please keep in mind that the\ncapabilities of this lock provider are really limited and that the whole ecosystem around R2DBC\nis in flux and may easily break.\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-r2dbc\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nand use it.\n\n```java\n@Override\nprotected LockProvider getLockProvider() {\n    return new R2dbcLockProvider(connectionFactory);\n}\n```\nI recommend using [R2DBC connection pool](https://github.com/r2dbc/r2dbc-pool).\n\n#### jOOQ lock provider\nFirst, create lock table as described in the [JdbcTemplate](#jdbctemplate) section above.\n\nAdd dependency\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-jooq\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.jooq;\n\n...\n@Bean\npublic LockProvider getLockProvider(DSLContext dslContext) {\n    return new JooqLockProvider(dslContext);\n}\n```\n\njOOQ provider has a bit different transactional behavior. While the other JDBC lock providers\ncreate new transaction (with REQUIRES_NEW), jOOQ [does not support setting it](https://github.com/jOOQ/jOOQ/issues/4836).\nShedLock tries to create a new transaction, but depending on your set-up, ShedLock DB operations may\nend-up being part of the enclosing transaction.\n\nIf you need to configure the table name, schema or column names, you can use jOOQ render mapping as\ndescribed [here](https://github.com/lukas-krecan/ShedLock/issues/1830#issuecomment-2015820509).\n\n#### Micronaut Data Jdbc\nIf you are using Micronaut data and you do not want to add dependency on Spring JDBC, you can use\nMicronaut JDBC support. Just be aware that it has just a basic functionality when compared to\nthe JdbcTemplate provider.\n\nFirst, create lock table as described in the [JdbcTemplate](#jdbctemplate) section above.\n\nAdd dependency\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-jdbc-micronaut\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.jdbc.micronaut.MicronautJdbcLockProvider;\n\n...\n@Singleton\npublic LockProvider lockProvider(TransactionOperations\u003cConnection\u003e transactionManager) {\n    return new MicronautJdbcLockProvider(transactionManager);\n}\n```\n\n#### Mongo\nImport the project\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-mongo\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.mongo.MongoLockProvider;\n\n...\n\n@Bean\npublic LockProvider lockProvider(MongoClient mongo) {\n    return new MongoLockProvider(mongo.getDatabase(databaseName))\n}\n```\n\nPlease note that MongoDB integration requires Mongo \u003e= 2.4 and mongo-java-driver \u003e= 3.7.0\n\n\n#### Reactive Mongo\nImport the project\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-mongo-reactivestreams\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.mongo.reactivestreams.ReactiveStreamsMongoLockProvider;\n\n...\n\n@Bean\npublic LockProvider lockProvider(MongoClient mongo) {\n    return new ReactiveStreamsMongoLockProvider(mongo.getDatabase(databaseName))\n}\n```\n\nPlease note that MongoDB integration requires Mongo \u003e= 4.x and mongodb-driver-reactivestreams 1.x\n\n\n#### DynamoDB 2\nDepends on AWS SDK v2.\n\nImport the project\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-dynamodb2\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.dynamodb2.DynamoDBLockProvider;\n\n...\n\n@Bean\npublic LockProvider lockProvider(software.amazon.awssdk.services.dynamodb.DynamoDbClient dynamoDB) {\n    return new DynamoDBLockProvider(dynamoDB, \"Shedlock\");\n}\n```\n\n\u003e Please note that the lock table must be created externally with `_id` as a partition key.\n\u003e `DynamoDBUtils#createLockTable` may be used for creating it programmatically.\n\u003e A table definition is available from `DynamoDBLockProvider`'s Javadoc.\n\n#### ZooKeeper (using Curator)\nImport\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-zookeeper-curator\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nand configure\n\n```java\nimport net.javacrumbs.shedlock.provider.zookeeper.curator.ZookeeperCuratorLockProvider;\n\n...\n\n@Bean\npublic LockProvider lockProvider(org.apache.curator.framework.CuratorFramework client) {\n    return new ZookeeperCuratorLockProvider(client);\n}\n```\nBy default, nodes for locks will be created under `/shedlock` node.\n\n#### Redis (using Spring RedisConnectionFactory)\nImport\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-redis-spring\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nand configure\n\n```java\nimport net.javacrumbs.shedlock.provider.redis.spring.RedisLockProvider;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\n\n...\n\n@Bean\npublic LockProvider lockProvider(RedisConnectionFactory connectionFactory) {\n    return new RedisLockProvider(connectionFactory, ENV);\n}\n```\n\n#### Redis (using Spring ReactiveRedisConnectionFactory)\nImport\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-redis-spring\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nand configure\n\n```java\nimport net.javacrumbs.shedlock.provider.redis.spring.ReactiveRedisLockProvider;\nimport org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;\n\n...\n\n@Bean\npublic LockProvider lockProvider(ReactiveRedisConnectionFactory connectionFactory) {\n    return new ReactiveRedisLockProvider.Builder(connectionFactory)\n        .environment(ENV)\n        .build();\n}\n```\n\nRedis lock provider uses classical lock mechanism as described [here](https://redis.io/commands/setnx#design-pattern-locking-with-codesetnxcode)\nwhich may not be reliable in case of Redis master failure.\n\n#### Redis (using Jedis)\nImport\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-redis-jedis4\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nand configure\n\n```java\nimport net.javacrumbs.shedlock.provider.redis.jedis.JedisLockProvider;\n\n...\n\n@Bean\npublic LockProvider lockProvider(JedisPool jedisPool) {\n    return new JedisLockProvider(jedisPool, ENV);\n}\n```\n\n#### Hazelcast\nImport the project\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-hazelcast4\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.hazelcast4.HazelcastLockProvider;\n\n...\n\n@Bean\npublic HazelcastLockProvider lockProvider(HazelcastInstance hazelcastInstance) {\n    return new HazelcastLockProvider(hazelcastInstance);\n}\n```\n\n#### Couchbase\nImport the project\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-couchbase-javaclient3\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.couchbase.javaclient.CouchbaseLockProvider;\n\n...\n\n@Bean\npublic CouchbaseLockProvider lockProvider(Bucket bucket) {\n    return new CouchbaseLockProvider(bucket);\n}\n```\n\nFor Couchbase 3 use `shedlock-provider-couchbase-javaclient3` module and `net.javacrumbs.shedlock.provider.couchbase3` package.\n\n#### Elasticsearch\nI 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\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-elasticsearch8\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport static net.javacrumbs.shedlock.provider.elasticsearch8.ElasticsearchLockProvider;\n\n...\n\n@Bean\npublic ElasticsearchLockProvider lockProvider(ElasticsearchClient client) {\n    return new ElasticsearchLockProvider(client);\n}\n```\n\n#### OpenSearch\nImport the project\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-opensearch\u003c/artifactId\u003e\n    \u003cversion\u003e4.36.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport static net.javacrumbs.shedlock.provider.opensearch.OpenSearchLockProvider;\n\n...\n\n@Bean\npublic OpenSearchLockProvider lockProvider(RestHighLevelClient highLevelClient) {\n    return new OpenSearchLockProvider(highLevelClient);\n}\n```\n\n#### CosmosDB\nCosmosDB support is provided by a third-party module available [here](https://github.com/jesty/shedlock-provider-cosmosdb)\n\n\n#### Cassandra\nImport the project\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-cassandra\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.cassandra.CassandraLockProvider;\nimport net.javacrumbs.shedlock.provider.cassandra.CassandraLockProvider.Configuration;\n\n...\n\n@Bean\npublic CassandraLockProvider lockProvider(CqlSession cqlSession) {\n    return new CassandraLockProvider(Configuration.builder().withCqlSession(cqlSession).withTableName(\"lock\").build());\n}\n```\n\nExample for creating default keyspace and table in local Cassandra instance:\n```sql\nCREATE KEYSPACE shedlock with replication={'class':'SimpleStrategy', 'replication_factor':1} and durable_writes=true;\nCREATE TABLE shedlock.lock (name text PRIMARY KEY, lockUntil timestamp, lockedAt timestamp, lockedBy text);\n```\n\nPlease, note that CassandraLockProvider uses Cassandra driver v4, which is part of Spring Boot since 2.3.\n\n#### Consul\nConsulLockProvider has one limitation: lockAtMostFor setting will have a minimum value of 10 seconds. It is dictated by consul's session limitations.\n\nImport the project\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-consul\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.consul.ConsulLockProvider;\n\n...\n\n@Bean // for micronaut please define preDestroy property @Bean(preDestroy=\"close\")\npublic ConsulLockProvider lockProvider(com.ecwid.consul.v1.ConsulClient consulClient) {\n    return new ConsulLockProvider(consulClient);\n}\n```\n\nPlease, note that Consul lock provider uses [ecwid consul-api client](https://github.com/Ecwid/consul-api), which is part of spring cloud consul integration (the `spring-cloud-starter-consul-discovery` package).\n\n#### ArangoDB\nImport the project\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-arangodb\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.arangodb.ArangoLockProvider;\n\n...\n\n@Bean\npublic ArangoLockProvider lockProvider(final ArangoOperations arangoTemplate) {\n    return new ArangoLockProvider(arangoTemplate.driver().db(DB_NAME));\n}\n```\n\nPlease, note that ArangoDB lock provider uses ArangoDB driver v6.7, which is part of [arango-spring-data](https://github.com/arangodb/spring-data) in version 3.3.0.\n\n#### Neo4j\nImport the project\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-neo4j\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n```java\nimport net.javacrumbs.shedlock.core.LockConfiguration;\n\n...\n\n@Bean\nNeo4jLockProvider lockProvider(org.neo4j.driver.Driver driver) {\n    return new Neo4jLockProvider(driver);\n}\n```\n\nPlease make sure that ```neo4j-java-driver``` version used by ```shedlock-provider-neo4j``` matches the driver version used in your\nproject (if you use `spring-boot-starter-data-neo4j`, it is probably provided transitively).\n\n#### Etcd\nImport the project\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-etcd-jetcd\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.etcd.jetcd.EtcdLockProvider;\n\n...\n\n@Bean\npublic LockProvider lockProvider(Client client) {\n    return new EtcdLockProvider(client);\n}\n```\n\n\n#### Apache Ignite\nImport the project\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-ignite\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure:\n\n```java\nimport net.javacrumbs.shedlock.provider.ignite.IgniteLockProvider;\n\n...\n\n@Bean\npublic LockProvider lockProvider(Ignite ignite) {\n    return new IgniteLockProvider(ignite);\n}\n```\n\n#### In-Memory\nIf you want to use a lock provider in tests there is an in-Memory implementation.\n\nImport the project\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-inmemory\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n    \u003cscope\u003etest\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\n```java\nimport net.javacrumbs.shedlock.provider.inmemory.InMemoryLockProvider;\n\n...\n\n@Bean\npublic LockProvider lockProvider() {\n    return new InMemoryLockProvider();\n}\n```\n\n#### Memcached (using spymemcached)\nPlease, be aware that memcached is not a database but a cache. It means that if the cache is full,\n[the lock may be released prematurely](https://stackoverflow.com/questions/6868256/memcached-eviction-prior-to-key-expiry/10456364#10456364)\n**Use only if you know what you are doing.**\n\nImport\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-memcached-spy\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nand configure\n\n```java\nimport net.javacrumbs.shedlock.provider.memcached.spy.MemcachedLockProvider;\n\n...\n\n@Bean\npublic LockProvider lockProvider(net.spy.memcached.MemcachedClient client) {\n    return new MemcachedLockProvider(client, ENV);\n}\n```\n\nP.S.:\n\nMemcached Standard Protocol:\n- A key (arbitrary string up to 250 bytes in length. No space or newlines for ASCII mode)\n- An expiration time, in `seconds`. '0' means never expire. Can be up to 30 days. After 30 days, is treated as a unix timestamp of an exact date. (support `seconds`、`minutes`、`days`, and less than `30` days)\n\n\n#### Datastore\n\nImport the project\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-datastore\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nand configure\n```java\nimport net.javacrumbs.shedlock.provider.datastore.DatastoreLockProvider;\n\n...\n\n@Bean\npublic LockProvider lockProvider(com.google.cloud.datastore.Datastore datastore) {\n    return new DatastoreLockProvider(datastore);\n}\n\n```\n#### Spanner\nImport the project\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003cartifactId\u003eshedlock-provider-spanner\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\nConfigure\n```java\nimport net.javacrumbs.shedlock.provider.spanner.SpannerLockProvider;\n\n...\n\n// Basic\n@Bean\npublic LockProvider lockProvider(DatabaseClient databaseClient) {\n    return new SpannerLockProvider(databaseClientSupplier);\n}\n\n// Custom host, table and column names\n@Bean\npublic LockProvider lockProvider(DatabaseClient databaseClient) {\n    var config = SpannerLockProvider.Configuration.builder()\n        .withDatabaseClient(databaseClientSupplier)\n        .withTableConfiguration(SpannerLockProvider.TableConfiguration.builder()\n            ...\n            // Custom table and column names\n            .build())\n        .withHostName(\"customHostName\")\n        .build();\n\n    return new SpannerLockProvider(config);\n}\n```\n\n\n## Multi-tenancy\nIf you have multi-tenancy use-case you can use a lock provider similar to this one\n(see the full [example](https://github.com/lukas-krecan/ShedLock/blob/master/providers/jdbc/shedlock-provider-jdbc-template/src/test/java/net/javacrumbs/shedlock/provider/jdbctemplate/MultiTenancyLockProviderIntegrationTest.java#L87))\n```java\nprivate static abstract class MultiTenancyLockProvider implements LockProvider {\n    private final ConcurrentHashMap\u003cString, LockProvider\u003e providers = new ConcurrentHashMap\u003c\u003e();\n\n    @Override\n    public @NonNull Optional\u003cSimpleLock\u003e lock(@NonNull LockConfiguration lockConfiguration) {\n        String tenantName = getTenantName(lockConfiguration);\n        return providers.computeIfAbsent(tenantName, this::createLockProvider).lock(lockConfiguration);\n    }\n\n    protected abstract LockProvider createLockProvider(String tenantName) ;\n\n    protected abstract String getTenantName(LockConfiguration lockConfiguration);\n}\n```\n\n## Customization\nYou can customize the behavior of the library by implementing `LockProvider` interface. Let's say you want to implement\na special behavior after a lock is obtained. You can do it like this:\n\n```java\npublic class MyLockProvider implements LockProvider {\n    private final LockProvider delegate;\n\n    public MyLockProvider(LockProvider delegate) {\n        this.delegate = delegate;\n    }\n\n    @Override\n    public Optional\u003cSimpleLock\u003e lock(LockConfiguration lockConfiguration) {\n        Optional\u003cSimpleLock\u003e lock = delegate.lock(lockConfiguration);\n        if (lock.isPresent()) {\n            // do something\n        }\n        return lock;\n    }\n}\n```\n\nYou can see a full example in [TrackingLockProviderWrapper](https://github.com/lukas-krecan/ShedLock/blob/master/shedlock-core/src/main/java/net/javacrumbs/shedlock/util/TrackingLockProviderWrapper.java)\n\n## Duration specification\nAll the annotations where you need to specify a duration support the following formats\n\n* duration+unit - `1s`, `5ms`, `5m`, `1d` (Since 4.0.0)\n* duration in ms - `100` (only Spring integration)\n* ISO-8601 - `PT15M` (see [Duration.parse()](https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html#parse-java.lang.CharSequence-) documentation)\n\n## Extending the lock\nThere are some use-cases which require to extend currently held lock. You can use LockExtender in the\nfollowing way:\n\n```java\nLockExtender.extendActiveLock(Duration.ofMinutes(5), ZERO);\n```\n\nPlease note that not all lock provider implementations support lock extension.\n\n## KeepAliveLockProvider\nThere is also KeepAliveLockProvider that is able to keep the lock alive by periodically extending it. It can be\nused by wrapping the original lock provider. My personal opinion is that it should be used only in special cases,\nit adds more complexity to the library and the flow is harder to reason about so please use moderately.\n\n```java\n@Bean\npublic LockProvider lockProvider(...) {\n    return new  KeepAliveLockProvider(new XyzProvider(...), scheduler);\n}\n```\nKeepAliveLockProvider extends the lock in the middle of the lockAtMostFor interval. For example, if the lockAtMostFor\nis 10 minutes the lock is extended every 5 minutes for 10 minutes until the lock is released. Please note that the minimal\nlockAtMostFor time supported by this provider is 30s. The scheduler is used only for the lock extension, single thread\nshould be enough.\n\n## Micronaut integration\nSince version 4.0.0, it's possible to use Micronaut framework for integration\n\nImport the project:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003c!-- Micronaut 3 --\u003e\n    \u003cartifactId\u003eshedlock-micronaut\u003c/artifactId\u003e\n    \u003c!-- For Micronaut 4 use --\u003e\n    \u003c!-- \u003cartifactId\u003eshedlock-micronaut4\u003c/artifactId\u003e --\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure default lockAtMostFor value (application.yml):\n```yaml\nshedlock:\n  defaults:\n    lock-at-most-for: 1m\n```\n\nConfigure lock provider:\n```java\n@Singleton\npublic LockProvider lockProvider() {\n    ... select and configure your lock provider\n}\n```\n\nConfigure the scheduled task:\n```java\n@Scheduled(fixedDelay = \"1s\")\n@SchedulerLock(name = \"myTask\")\npublic void myTask() {\n    assertLocked();\n    ...\n}\n```\n\n## CDI integration\nSince version 5.0.0, it's possible to use CDI for integration (tested only with Quarkus)\n\nImport the project:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.javacrumbs.shedlock\u003c/groupId\u003e\n    \u003c!-- use shedlock-cdi-vintage for quarkus 2.x --\u003e\n    \u003cartifactId\u003eshedlock-cdi\u003c/artifactId\u003e\n    \u003cversion\u003e5.16.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nConfigure default lockAtMostFor value (application.properties):\n```properties\nshedlock.defaults.lock-at-most-for=PT30S\n```\n\nConfigure lock provider:\n```java\n@Produces\n@Singleton\npublic LockProvider lockProvider() {\n        ...\n}\n```\n\nConfigure the scheduled task:\n```java\n@Scheduled(every = \"1s\")\n@SchedulerLock(name = \"myTask\")\npublic void myTask() {\n    assertLocked();\n    ...\n}\n```\n\nThe implementation only depends on `jakarta.enterprise.cdi-api` and `microprofile-config-api` so it should be\nusable in other CDI compatible frameworks, but it has not been tested with anything else than Quarkus. It's\nbuilt on top of javax annotation as Quarkus has not moved to Jakarta EE namespace yet.\n\nThe support is minimalistic, for example there is no support for expressions in the annotation parameters yet,\nif you need it, feel free to send a PR.\n\n## Locking without a framework\nIt is possible to use ShedLock without a framework\n\n```java\nLockingTaskExecutor executor = new DefaultLockingTaskExecutor(lockProvider);\n\n...\nInstant createdAt = Instant.now();\nDuration lockAtMostFor = Duration.ofSeconds(60);\nDuration lockAtLeastFor = Duration.ZERO;\nexecutor.executeWithLock(runnable, new LockConfiguration(createdAt, \"lockName\", lockAtMostFor, lockAtLeastFor));\n\n```\n\n## Extending the lock\nSome lock providers support extension of the lock. For the time being, it requires manual lock manipulation,\ndirectly using `LockProvider` and calling `extend` method on the `SimpleLock`.\n\n## Modes of Spring integration\nShedLock supports two modes of Spring integration. One that uses an AOP proxy around scheduled method (PROXY_METHOD)\nand one that proxies TaskScheduler (PROXY_SCHEDULER)\n\n#### Scheduled Method proxy\nSince version 4.0.0, the default mode of Spring integration is an AOP proxy around the annotated method.\n\nThe main advantage of this mode is that it plays well with other frameworks that want to somehow alter the default Spring scheduling mechanism.\nThe disadvantage is that the lock is applied even if you call the method directly. If the method returns a value and the lock is held\nby another process, null or an empty Optional will be returned (primitive return types are not supported).\n\nFinal and non-public methods are not proxied so either you have to make your scheduled methods public and non-final or use TaskScheduler proxy.\n\n![Method proxy sequenceDiagram](https://github.com/lukas-krecan/ShedLock/raw/master/documentation/method_proxy.png)\n\n#### TaskScheduler proxy\nThis mode wraps Spring `TaskScheduler` in an AOP proxy. **This mode does not play well with instrumentation libraries**\nlike opentelementry that also wrap TaskScheduler. Please only use it if you know what you are doing.\nIt can be switched-on like this (PROXY_SCHEDULER was the default method before 4.0.0):\n\n```java\n@EnableSchedulerLock(interceptMode = PROXY_SCHEDULER)\n```\n\nIf 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`\ninterface and it will get wrapped into the AOP proxy automatically.\n\n```java\n@Bean\npublic TaskScheduler taskScheduler() {\n    return new MySpecialTaskScheduler();\n}\n```\n\nAlternatively, you can define a bean of type `ScheduledExecutorService` and it will automatically get used by the tasks\nscheduling mechanism.\n\n![TaskScheduler proxy sequence diagram](https://github.com/lukas-krecan/ShedLock/raw/master/documentation/scheduler_proxy.png)\n\n### Spring XML configuration\nSpring XML configuration is not supported as of version 3.0.0. If you need it, please use version 2.6.0 or file an issue explaining why it is needed.\n\n## Lock assert\nTo prevent misconfiguration errors, like AOP misconfiguration, missing annotation etc., you can assert that the lock\nworks by using LockAssert:\n\n```java\n@Scheduled(...)\n@SchedulerLock(..)\npublic void scheduledTask() {\n    // To assert that the lock is held (prevents misconfiguration errors)\n    LockAssert.assertLocked();\n    // do something\n}\n```\n\nIn unit tests you can switch-off the assertion by calling `LockAssert.TestHelper.makeAllAssertsPass(true)` on given thread (as in this [example](https://github.com/lukas-krecan/ShedLock/commit/e8d63b7c56644c4189e0a8b420d8581d6eae1443)).\n\n## Kotlin gotchas\nThe 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`\nannotation, everything should work since Kotlin Spring compiler plugin will automatically 'open' the method for you. If `@Component` annotation is not present, you\nhave to open the method by yourself. (see [this issue](https://github.com/lukas-krecan/ShedLock/issues/1268) for more details)\n\n## Caveats\nLocks in ShedLock have an expiration time which leads to the following possible issues.\n1. If the task runs longer than `lockAtMostFor`, the task can be executed more than once\n2. If the clock difference between two nodes is more than `lockAtLeastFor` or minimal execution time the task can be\nexecuted more than once.\n\n## Troubleshooting\nHelp, ShedLock does not do what it's supposed to do!\n\n1. Upgrade to the newest version\n2. Use [LockAssert](https://github.com/lukas-krecan/ShedLock#lock-assert) to ensure that AOP is correctly configured.\n   - If it does not work, please read about Spring AOP internals (for example [here](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-proxying))\n3. Check the storage. If you are using JDBC, check the ShedLock table. If it's empty, ShedLock is not properly configured.\nIf there is more than one record with the same name, you are missing a primary key.\n4. Use ShedLock debug log. ShedLock logs interesting information on DEBUG level with logger name `net.javacrumbs.shedlock`.\nIt should help you to see what's going on.\n5. For short-running tasks consider using `lockAtLeastFor`. If the tasks are short-running, they could be executed one\nafter another, `lockAtLeastFor` can prevent it.\n\n\n# Release notes\n\n## 5.16.0 (2024-09-06)\n* Support for custome partition key for Dynamo #2128 (thanks @kumar-himans)\n* Upgrade OpenSearch rest-high-level-client #2115 - Breaking change due to rest-high-level-client backward incompatibility\n* Dependency updates\n\n## 5.15.1 (2024-08-27)\n* Fix for Neo4j Enterprise #2099 (thanks @tle130475c)\n* Dependency updates\n\n## 5.15.0 (2024-08-15)\n* Dependency updates\n* ElasticSearch updated to 8.15.0 containing backward incompatible change (thanks @mputz86)\n\n## 5.14.0 + 4.48.0 (2024-07-24)\n* RedisLockProvider made extensible (thanks @shubhajyoti-bagchi-groww)\n* Dependency updates\n\n## 5.13.0 (2024-04-05)\n* #1779 Ability to rethrow unexpected exception in JdbcTemplateStorageAccessor\n* Dependency updates\n\n## 5.12.0 (2024-02-29)\n* #1800 Enable lower case for database type when using usingDbTime()\n* #1804 Startup error with Neo4j 5.17.0\n* Dependency updates\n\n## 4.47.0 (2024-03-01)\n* #1800 Enable lower case for database type when using usingDbTime() (thanks @yuagu1)\n\n## 5.11.0 (2024-02-13)\n* #1753 Fix SpEL for methods with parameters\n* Dependency updates\n\n## 5.10.2 (2023-12-07)\n* #1635 fix makeAllAssertsPass locks only once\n* Dependency updates\n\n## 5.10.1 (2023-12-06)\n* #1635 fix makeAllAssertsPass(false) throws NoSuchElementException\n* Dependency updates\n\n## 5.10.0 (2023-11-07)\n* SpannerLockProvider added (thanks @pXius)\n* Dependency updates\n\n## 5.9.1 (2023-10-19)\n* QuarkusRedisLockProvider supports Redis 6.2 (thanks  @ricardojlrufino)\n\n## 5.9.0 (2023-10-15)\n* Support Quarkus 2 Redis client (thanks  @ricardojlrufino)\n* Better handling of timeouts in ReactiveStreamsMongoLockProvider\n* Dependency updates\n\n## 5.8.0 (2023-09-15)\n* Support for Micronaut 4\n* Use Merge instead of Insert for Oracle #1528 (thanks @xmojsic)\n* Dependency updates\n\n## 5.7.0 (2023-08-25)\n* JedisLockProvider supports extending (thanks @shotmk)\n* Better behavior when locks are nested #1493\n\n## 4.46.0 (2023-09-05)\n* JedisLockProvider (version 3) supports extending (thanks @shotmk)\n\n## 4.45.0 (2023-09-04)\n* JedisLockProvider supports extending (thanks @shotmk)\n\n## 5.6.0\n* Ability to explicitly set database product in JdbTemplateLockProvider (thanks @metron2)\n* Removed forgotten versions from BOM\n* Dependency updates\n\n## 5.5.0 (2023-06-19)\n* Datastore support (thanks @mmastika)\n* Dependency updates\n\n## 5.4.0 (2023-06-06)\n* Handle [uncategorized SQL exceptions](https://github.com/lukas-krecan/ShedLock/pull/1442) (thanks @jaam)\n* Dependency updates\n\n## 5.3.0 (2023-05-13)\n* Added shedlock-cdi module (supports newest CDI version)\n* Dependency updates\n\n## 5.2.0 (2023-03-06)\n* Uppercase in JdbcTemplateProvider (thanks @Ragin-LundF)\n* Dependency updates\n\n## 5.1.0 (2023-01-07)\n* Added SpEL support to @SchedulerLock name attribute (thanks @ipalbeniz)\n* Dependency updates\n\n## 5.0.1 (2022-12-10)\n* Work around broken Spring 6 exception translation https://github.com/lukas-krecan/ShedLock/issues/1272\n\n## 4.44.0 (2022-12-29)\n* Insert ignore for MySQL https://github.com/lukas-krecan/ShedLock/commit/8a4ae7ad8103bb47f55d43bccf043ca261c24d7a\n\n## 5.0.0 (2022-12-10)\n* Requires JDK 17\n* Tested with Spring 6 (Spring Boot 3)\n* Micronaut updated to 3.x.x\n* R2DBC 1.x.x (still sucks)\n* Spring Data 3.x.x\n* Rudimentary support for CDI (tested with quarkus)\n* New jOOQ lock provider\n* SLF4j 2\n* Deleted all deprecated code and support for old versions of libraries\n\n## 4.43.0 (2022-12-04)\n* Better logging in JdbcTemplateProvider\n* Dependency updates\n\n## 4.42.0 (2022-09-16)\n* Deprecate old Couchbase lock provider\n* Dependency updates\n\n## 4.41.0 (2022-08-17)\n* Couchbase collection support (thanks @mesuutt)\n* Dependency updates\n\n## 4.40.0 (2022-08-11)\n* Fixed caching issues when the app is started by the DB does not exist yet (#1129)\n* Dependency updates\n\n## 4.39.0 (2022-07-26)\n* Introduced elasticsearch8 LockProvider and deperecated the orignal one (thanks @MarAra)\n* Dependency updates\n\n## 4.38.0 (2022-07-02)\n* ReactiveRedisLockProvider added (thanks @ericwcc)\n* Dependency updates\n\n## 4.37.0 (2022-06-14)\n* OpenSearch provider (thanks @Pinny3)\n* Fix wrong reference to reactive Mongo in BOM #1048\n* Dependency updates\n\n## 4.36.0 (2022-05-28)\n* shedlock-bom module added\n* Dependency updates\n\n## 4.35.0 (2022-05-16)\n* Neo4j allows to specify database thanks @SergeyPlatonov\n* Dependency updates\n\n## 4.34.0 (2022-04-09)\n* Dropped support for Hazelcast \u003c= 3 as it has unfixed vulnerability\n* Dropped support for Spring Data Redis 1 as it is not supported\n* Dependency updates\n\n## 4.33.0\n* memcached provider added (thanks @pinkhello)\n* Dependency updates\n\n## 4.32.0\n* JDBC provider does not change autocommit attribute\n* Dependency updates\n\n## 4.31.0\n* Jedis 4 lock provider\n* Dependency updates\n\n## 4.30.0\n* In-memory lock provider added (thanks @kkocel)\n* Dependency updates\n\n## 4.29.0\n* R2DBC support added (thanks @sokomishalov)\n* Library upgrades\n\n## 4.28.0\n* Neo4j lock provider added (thanks @thimmwork)\n* Library upgrades\n\n## 4.27.0\n* Ability to set transaction isolation in JdbcTemplateLockProvider\n* Library upgrades\n\n## 4.26.0\n* KeepAliveLockProvider introduced\n* Library upgrades\n\n## 4.25.0\n* LockExtender added\n\n## 4.24.0\n* Support for Apache Ignite (thanks @wirtsleg)\n* Library upgrades\n\n## 4.23.0\n* Ability to set serialConsistencyLevel in Cassandra (thanks @DebajitKumarPhukan)\n* Introduced shedlock-provider-jdbc-micronaut module (thanks @drmaas)\n\n## 4.22.1\n* Catching and logging Cassandra exception\n\n## 4.22.0\n* Support for custom keyspace in Cassandra provider\n\n## 4.21.0\n* Elastic unlock using IMMEDIATE refresh policy #422\n* DB2 JDBC lock provider uses microseconds in DB time\n* Various library upgrades\n\n## 4.20.1\n* Fixed DB JDBC server time #378\n\n## 4.20.0\n* Support for etcd (thanks grofoli)\n\n## 4.19.1\n* Fixed devtools compatibility #368\n\n## 4.19.0\n* Support for enhanced configuration in Cassandra provider (thanks DebajitKumarPhukan)\n* LockConfigurationExtractor exposed as a Spring bean #359\n* Handle CannotSerializeTransactionException #364\n\n## 4.18.0\n* Fixed Consul support for tokens and added enhanced Consul configuration (thanks DrWifey)\n\n## 4.17.0\n* Consul support for tokens\n\n## 4.16.0\n* Spring - EnableSchedulerLock.order param added to specify AOP proxy order\n* JDBC - Log unexpected exceptions at ERROR level\n* Hazelcast upgraded to 4.1\n\n## 4.15.1\n* Fix session leak in Consul provider #340 (thanks @haraldpusch)\n\n## 4.15.0\n* ArangoDB lock provider added (thanks @patrick-birkle)\n\n## 4.14.0\n* Support for Couchbase 3 driver (thanks @blitzenzzz)\n* Removed forgotten configuration files form micronaut package (thanks @drmaas)\n* Shutdown hook for Consul (thanks @kaliy)\n\n## 4.13.0\n* Support for Consul (thanks @kaliy)\n* Various dependencies updated\n* Deprecated default LockConfiguration constructor\n\n## 4.12.0\n* Lazy initialization of SqlStatementsSource #258\n\n## 4.11.1\n* MongoLockProvider uses mongodb-driver-sync\n* Removed deprecated constructors from MongoLockProvider\n\n## 4.10.1\n* New Mongo reactive streams driver (thanks @codependent)\n\n## 4.9.3\n* Fixed JdbcTemplateLockProvider useDbTime() locking #244 thanks @gjorgievskivlatko\n\n## 4.9.2\n* Do not fail on DB type determining code if DB connection is not available\n\n## 4.9.1\n* Support for server time in DB2\n* removed shedlock-provider-jdbc-internal module\n\n## 4.9.0\n* Support for server time in JdbcTemplateLockProvider\n* Using custom non-null annotations\n* Trimming time precision to milliseconds\n* Micronaut upgraded to 1.3.4\n* Add automatic DB tests for Oracle, MariaDB and MS SQL.\n\n## 4.8.0\n* DynamoDB 2 module introduced (thanks Mark Egan)\n* JDBC template code refactored to not log error on failed insert in Postgres\n    * INSERT .. ON CONFLICT UPDATE is used for Postgres\n\n## 4.7.1\n* Make LockAssert.TestHelper public\n\n## 4.7.0\n* New module for Hazelcasts 4\n* Ability to switch-off LockAssert in unit tests\n\n## 4.6.0\n* Support for Meta annotations and annotation inheritance in Spring\n\n## 4.5.2\n* Made compatible with PostgreSQL JDBC Driver 42.2.11\n\n## 4.5.1\n* Inject redis template\n\n## 4.5.0\n* ClockProvider introduced\n* MongoLockProvider(MongoDatabase) introduced\n\n## 4.4.0\n* Support for non-void returning methods when PROXY_METHOD interception is used\n\n## 4.3.1\n* Introduced shedlock-provider-redis-spring-1 to make it work around Spring Data Redis 1 issue #105 (thanks @rygh4775)\n\n## 4.3.0\n* Jedis dependency upgraded to 3.2.0\n* Support for JedisCluster\n* Tests upgraded to JUnit 5\n\n## 4.2.0\n* Cassandra provider (thanks @mitjag)\n\n## 4.1.0\n* More configuration option for JdbcTemplateProvider\n\n## 4.0.4\n* Allow configuration of key prefix in RedisLockProvider #181 (thanks @krm1312)\n\n## 4.0.3\n* Fixed junit dependency scope #179\n\n## 4.0.2\n* Fix NPE caused by Redisson #178\n## 4.0.1\n* DefaultLockingTaskExecutor made reentrant #175\n## 4.0.0\nVersion 4.0.0 is a major release changing quite a lot of stuff\n* `net.javacrumbs.shedlock.core.SchedulerLock` has been replaced by `net.javacrumbs.shedlock.spring.annotation.SchedulerLock`. The original annotation has been in wrong module and\nwas too complex. Please use the new annotation, the old one still works, but in few years it will be removed.\n* Default intercept mode changed from `PROXY_SCHEDULER` to `PROXY_METHOD`. The reason is that there were a lot of issues with  `PROXY_SCHEDULER` (for example #168). You can still\nuse `PROXY_SCHEDULER` mode if you specify it manually.\n* Support for more readable [duration strings](#duration-specification)\n* Support for lock assertion `LockAssert.assertLocked()`\n* [Support for Micronaut](#micronaut-integration) added\n\n## 3.0.1\n* Fixed bean definition configuration #171\n\n## 3.0.0\n* `EnableSchedulerLock.mode` renamed to `interceptMode`\n* Use standard Spring AOP configuration to honor Spring Boot config (supports `proxyTargetClass` flag)\n* Removed deprecated SpringLockableTaskSchedulerFactoryBean and related classes\n* Removed support for XML configuration\n\n## 2.6.0\n* Updated dependency to Spring 2.1.9\n* Support for lock extensions (beta)\n\n## 2.5.0\n* Zookeeper supports *lockAtMostFor* and *lockAtLeastFor* params\n* Better debug logging\n\n## 2.4.0\n* Fixed potential deadlock in Hazelcast (thanks @HubertTatar)\n* Finding class level annotation in proxy method mode (thanks @volkovs)\n* ScheduledLockConfigurationBuilder deprecated\n\n## 2.3.0\n* LockProvides is initialized lazilly so it does not change DataSource initialization order\n\n## 2.2.1\n* MongoLockProvider accepts MongoCollection as a constructor param\n\n## 2.2.0\n* DynamoDBLockProvider added\n\n## 2.1.0\n* MongoLockProvider rewritten to use upsert\n* ElasticsearchLockProvider added\n\n## 2.0.1\n* AOP proxy and annotation configuration support\n\n## 1.3.0\n* Can set Timezone to JdbcTemplateLock provider\n\n## 1.2.0\n* Support for Couchbase (thanks to @MoranVaisberg)\n\n## 1.1.1\n* Spring RedisLockProvider refactored to use RedisTemplate\n\n## 1.1.0\n* Support for transaction manager in JdbcTemplateLockProvider (thanks to @grmblfrz)\n\n## 1.0.0\n* Upgraded dependencies to Spring 5 and Spring Data 2\n* Removed deprecated net.javacrumbs.shedlock.provider.jedis.JedisLockProvider (use  net.javacrumbs.shedlock.provider.redis.jedis.JedisLockProvide instead)\n* Removed deprecated SpringLockableTaskSchedulerFactory (use ScheduledLockConfigurationBuilder instead)\n\n## 0.18.2\n* ablility to clean lock cache\n\n## 0.18.1\n* shedlock-provider-redis-spring made compatible with spring-data-redis 1.x.x\n\n## 0.18.0\n* Added shedlock-provider-redis-spring (thanks to @siposr)\n* shedlock-provider-jedis moved to shedlock-provider-redis-jedis\n\n## 0.17.0\n* Support for SPEL in lock name annotation\n\n## 0.16.1\n* Automatically closing TaskExecutor on Spring shutdown\n\n## 0.16.0\n* Removed spring-test from shedlock-spring compile time dependencies\n* Added Automatic-Module-Names\n\n## 0.15.1\n* Hazelcast works with remote cluster\n\n## 0.15.0\n* Fixed ScheduledLockConfigurationBuilder interfaces #32\n* Hazelcast code refactoring\n\n## 0.14.0\n* Support for Hazelcast (thanks to @peyo)\n\n## 0.13.0\n* Jedis constructor made more generic (thanks to @mgrzeszczak)\n\n## 0.12.0\n* Support for property placeholders in annotation lockAtMostForString/lockAtLeastForString\n* Support for composed annotations\n* ScheduledLockConfigurationBuilder introduced (deprecating SpringLockableTaskSchedulerFactory)\n\n## 0.11.0\n* Support for Redis (thanks to @clamey)\n* Checking that lockAtMostFor is in the future\n* Checking that lockAtMostFor is larger than lockAtLeastFor\n\n\n## 0.10.0\n* jdbc-template-provider does not participate in task transaction\n\n## 0.9.0\n* Support for @SchedulerLock annotations on proxied classes\n\n## 0.8.0\n* LockableTaskScheduler made AutoClosable so it's closed upon Spring shutdown\n\n## 0.7.0\n* Support for lockAtLeastFor\n\n## 0.6.0\n* Possible to configure defaultLockFor time so it does not have to be repeated in every annotation\n\n## 0.5.0\n* ZooKeeper nodes created under /shedlock by default\n\n## 0.4.1\n* JdbcLockProvider insert does not fail on DataIntegrityViolationException\n\n## 0.4.0\n* Extracted LockingTaskExecutor\n* LockManager.executeIfNotLocked renamed to executeWithLock\n* Default table name in JDBC lock providers\n\n## 0.3.0\n* `@ShedlulerLock.name` made obligatory\n* `@ShedlulerLock.lockForMillis` renamed to lockAtMostFor\n* Adding plain JDBC LockProvider\n* Adding ZooKeepr LockProvider\n","funding_links":[],"categories":["Java","Projects","项目","分布式开发","\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":["Job Scheduling","作业调度"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukas-krecan%2FShedLock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flukas-krecan%2FShedLock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukas-krecan%2FShedLock/lists"}