Use Spring Scheduler In Clustered Environment

Suchit Gupta
2 min readJun 26, 2020

At most once at the same time in Spring Scheduler.

Spring Scheduler is an easy and efficient way of scheduling the tasks. However, one caveat is in case of multiple instances it fires the task on every instance. This behavior is not ideal for use cases where the expected behavior is at most once at the same time.

I have been using quartz for scheduling the jobs but recently came across Shedlock which makes scheduling much easier.

Spring-Scheduler with Shedlock

Spring-Scheduler triggers all the instances, Shedlock initiates a race condition and whichever instances are able to win takes control over the task and other instances silently exit the task.

How to implement Shedlock?

Step 1: Create a table that would be used by Shedlock to trigger the race condition.

CREATE TABLE IF NOT EXISTS shedlock(name VARCHAR(64) NOT NULL, locked_at TIMESTAMP NOT NULL, lock_until TIMESTAMP NOT NULL, locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));

Step 2: Enable Schedlock and create SheldLock Lock Provider.

import javax.sql.DataSource;
import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "30s")
@EnableScheduling
public class ShedLockConfig {

@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource, "shedlock");
}

}

Step 3 Create a Spring Scheduler task with Shedlock.

import java.text.SimpleDateFormat;
import java.util.Date;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduledCurrentTimeTask {

private static final Logger log = LoggerFactory.getLogger(ScheduledCurrentTimeTask.class);

private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

@Scheduled(fixedRate = 5000)
@SchedulerLock(name = "currentTimeTask", lockAtLeastFor = "5S", lockAtMostFor = "10M")
public void currentTimeTask() {
log.info("The time is now {}", dateFormat.format(new Date()));
}

}

The three steps and now Spring Scheduler is At most once at the same time in Spring Scheduler.

Sample Code

Download the sample code from Github.

--

--