I used Spring Task Scheduler with Shedlock and Redis to make scheduled task execution distributable.
In my XML configuration file I specify the task scheduler:
<task:scheduler id="myScheduler" pool-size="4"/>
<task:annotation-driven scheduler="myScheduler" />
In SchedulerLockConfiguration.java I create the LockProvider Spring bean and set up the Redis connection and the Jedis connection pool:
@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "PT10H")
public class SchedulerLockConfiguration {
@Bean
public JedisPool jedisPool() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(100); // The maximum number of connections that are supported by the pool
jedisPoolConfig.setMaxIdle(100); // The maximum number of idle connections in the pool
jedisPoolConfig.setMinIdle(10); // The minimum number of idle connections in the pool
return new JedisPool(
jedisPoolConfig,
Constants.REDIS_HOSTNAME,
Integer.parseInt(Constants.REDIS_PORT),
Integer.parseInt(Constants.REDIS_SESSION_TIMEOUT),
null,
Constants.REDIS_DATABASE_SHEDLOCK);
}
@Bean
public LockProvider lockProvider(JedisPool jedisPool) {
return new JedisLockProvider(jedisPool, "yourRedisNamespace");
}
}
...then finally, I use @Scheduled and @SchedulerLock annotations on the methods I want to schedule:
@Scheduled(cron = "${my.cron.expression}")
@SchedulerLock(name = "myScheduler", lockAtLeastFor = "PT10M")
public void processDelayedAutomationRules() { ... }
When a @Scheduled job's cron kicks in, whichever applciation instance / server node puts the lock faster into the Redis store, that'll be the one executing it.