varunkr
varunkr

Reputation: 5542

ShedLock: Running multiple instances runs scheduler tasks multiple times

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

Answers (5)

Ramesh Kandari
Ramesh Kandari

Reputation: 21

Please try with cron expression inside @scheduled instead of fixedDelayString, below scheduler run every hour.

@Scheduled(cron = "0 */1 * * *")

Upvotes: 2

B J
B J

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

Saber Chebka
Saber Chebka

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

user1973594
user1973594

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

Will Hughes
Will Hughes

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

Related Questions