I am looking to replace Quartz as a job scheduler in our project. We already use Redis with cluster support as a distributed cache layer and we thought that maybe we could use Redis for job scheduling too. Has anyone implemented job scheduling in Java using Redis? I searched but could not find a library for this purpose. So I am starting to think that this is maybe not a popular solution?
-
Did you take a look into https://github.com/antirez/disque? – mp911de Mar 27 '16 at 11:17
3 Answers
Take a look at Redisson. It allows to schedule and execute tasks (with cron-expression support) using simple ScheduledExecutorService api and based on Redis queue.
Here is an example. First define a task using java.lang.Runnable
interface. Each task can access to Redis instance via injected RedissonClient
object.
public class RunnableTask implements Runnable {
@RInject
private RedissonClient redissonClient;
@Override
public void run() throws Exception {
RMap<String, Integer> map = redissonClient.getMap("myMap");
Long result = 0;
for (Integer value : map.values()) {
result += value;
}
redissonClient.getTopic("myMapTopic").publish(result);
}
}
Submit it to Redis based ExecutorService.
RScheduledExecutorService executorService = redisson.getExecutorService("myExecutor");
RScheduledFuture<?> future = executorService.schedule(new CallableTask(), 10, 20, TimeUnit.MINUTES);
future.get();
// or cancel it
future.cancel(true);
// cancel by taskId
executorService.cancelTask(future.getTaskId());
Examples with cron expressions:
executorService.schedule(new RunnableTask(), CronSchedule.of("10 0/5 * * * ?"));
executorService.schedule(new RunnableTask(), CronSchedule.dailyAtHourAndMinute(10, 5));
executorService.schedule(new RunnableTask(), CronSchedule.weeklyOnDayAndHourAndMinute(12, 4, Calendar.MONDAY, Calendar.FRIDAY));
All tasks are distributed across Redisson nodes. You can run these nodes as much as you need.

- 10,283
- 1
- 62
- 71
How about Redis Labs' redis-quartz:
RedisJobStore A Quartz Scheduler JobStore that uses Redis for persistent storage.
We'd appreciate any feedback you have :)

- 47,336
- 7
- 91
- 117
-
2
-
Doesn't appear so - redis-quartz uses pipelined mode which, AFAIR, isn't supported by JedisCluster atm. Changing redis-quartz to not do that looks easy, so feel free to test/submit an issue/feature request/pull request if that's important to you. That said, unless you expect your job store to be massively loaded, I don't quite see the reason for a clustered deployment unless it is an existing one. If that is the case, note that in 99.999% of the cases you'd be better off using dedicated Redis databases for each task rather than trying use a single DB for everything. – Itamar Haber Mar 25 '16 at 16:06
-
Oh, there's an existing issue for that already: https://github.com/RedisLabs/redis-quartz/issues/6 #facepalm - want to add your say to it? – Itamar Haber Mar 25 '16 at 16:21
-
1@ItamarHaber Pipelining works nicely with cluster, it's just the async nature that can make you cry when slots move. – mp911de Mar 27 '16 at 11:16
-
@mp911de I was referring specifically to Jedis' pipelining according to https://groups.google.com/forum/#!msg/jedis_redis/u6j8slokO3E/Dh5Q94TRjJUJ – Itamar Haber Mar 27 '16 at 15:29
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.

- 2,077
- 20
- 23