Reputation: 5542
I am using Shedlock
to run my scheduler
task only once if multiple instances of the service are running.
I followed the documentation and this is what I did.
This is the function that needs to run periodically
@Scheduled(fixedDelayString = "300000")
@SchedulerLock(name = "onlineIngestionTask", lockAtMostFor = 240000, lockAtLeastFor = 240000)
public void pullTasksFromRemote() {
//Code
}
In my config class I have the following beans
@Bean
public ScheduledLockConfiguration taskScheduler(LockProvider lockProvider) {
return ScheduledLockConfigurationBuilder
.withLockProvider(lockProvider)
.withPoolSize(10)
.withDefaultLockAtMostFor(Duration.ofMinutes(10))
.build();
}
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
The pom includes
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>0.14.0</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>0.14.0</version>
</dependency>
I added a table to my db, the one to which jdbc connects.
CREATE TABLE shedlock(
name VARCHAR(64),
lock_until TIMESTAMP(3) NULL,
locked_at TIMESTAMP(3) NULL,
locked_by VARCHAR(255),
PRIMARY KEY (name)
)
After this I tried to test the functionality by running tha pp first on port 8080. Then I use server.port=9000
to run it again on port 9000. But both these instances start running the task. Am I missing something. Is something wrong in the implementation? Can someone give any ideas. Thanks !!
Upvotes: 5
Views: 28277
Reputation: 21
Please try with cron expression inside @scheduled
instead of fixedDelayString
, below scheduler run every hour.
@Scheduled(cron = "0 */1 * * *")
Upvotes: 2
Reputation: 1
Shedlock guarantees only that the given method won't be executed twice within lock constraints (so taking into account method execution time and defaultLockAtMostFor/defaultLockAtLeastFor parameters). By default Spring uses only one thread for scheduled tasks, which (if one job runs much longer than another, or longer than defaultLockAtLeastFor) may cause for second instance to execute given method when lock is already released. Inmy case adding
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
private final int POOL_SIZE = 10;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
threadPoolTaskScheduler.setThreadNamePrefix("scheduled-task-pool-");
threadPoolTaskScheduler.initialize();
taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
resolved the issue.
Upvotes: 0
Reputation: 107
It is a good challenge to implement the lock yourself using java annotations and aop (Aspect oriented) programming.
Not so complicated to do. A kind of:
@Around(" @annotation(com.company.MyLock)")
Then use the annotation around the scheduler processing method.
Upvotes: -1
Reputation: 41
we recently had this issue in prod where we could see multiple runs of shedlock schedulers. if you are using spring boot 2.2.1.RELEASE onwards then use below deps for shedlock
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>4.9.3</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-redis-spring</artifactId>
<version>4.8.0</version>
</dependency>
Upvotes: 2
Reputation: 367
dlock guarantees to have one lock at any time by using database indexes and constraints. You can simply do something like below.
@Scheduled(cron = "30 30 3 * * *")
@TryLock(name = "onlineIngestionTask", owner = SERVER_NAME, lockFor = 240000)
public void pullTasksFromRemote() {
}
See the article about using it.
Upvotes: 3