Spring Boot ShedLock solves a very common problem which occurs if you are running scheduled cron jobs in your application which is deployed in a distributed environment with shared database.
Spring by default, doesn’t provide a way to handle synchronization of cron jobs between multiple instance. It means spring will run your scheduler on multiple instances at the same time. ShedLock solves this problem. It will make sure your task with @Scheduled annotation is run only on one instance in your deployment setup. Spring Boot ShedLock uses external storage to keep a track of schedulers and locks. You need to have your application connected to a database for this to work. Check out: ShedLock on github.
Here are the steps to integrate shedlock in your spring boot applications. Make sure to go on to the github page of shedlock to read more about it.
Add ShedLock Dependency
Add maven dependency for Spring Boot ShedLock to you pom.xml
.
<dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>4.24.0</version> </dependency>
Create ShedLock Table
Depending on your database, create a table for ShedLock. Here is an example of MySQL
table for shedlock:
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) );
Annotate your application with the ShedLock annotation
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S") public class YourApplicationWithSchedulers { public static void main(String[] args) { SpringApplication.run(YourApplicationWithSchedulers.class, args); } }
Define LockProvider Bean
You can define this bean in your main application file, or just create a new configuration class.
@Configuration public class ShedLockConfig { @Bean public LockProvider lockProvider(DataSource dataSource) { return new JdbcTemplateLockProvider(dataSource); } }
Annotate Your Schedulers
The last thing you need to do is to annotate your schedulers.
public class YourTaskScheduler { @Scheduled(cron = "0 * * ? * *") @SchedulerLock( name = "UNIQUE_KEY_FOR_THIS_SCHEDULER", lockAtLeastForString = "PT1M", // lock for at least a minute, overriding the default setting here for each scheduler lockAtMostForString = "PT5M" // lock for at most 5 minutes ) public void run() { // your task }
That’s it. The annotated schedulers will be locked for execution when one of your instance starts executing it and will not be executed concurrently on other instances.
You can check out ShedLock github for other databases and time durations. Let me know if this helped.