Persistent job scheduling without Quartz

Have you ever had the need for scheduling background tasks but always wanted a more lightweight alternative to Quartz Scheduler?

2 min read


By Even Holthe


December 12, 2019

Introducing a lightweight alternative

Running background tasks is an important part of backend software. In the Java ecosystem, one of the most used schedulers for running background tasks is the Quartz Scheduler. It is simply a beast in terms of functionality and can be in form of complexity.

Gustav Karlsson (Bekk) longed for a more lightweight alternative himself, one which did not require 11 database tables to function. He wound up writing his own alternative scheduler – db-scheduler – which just requires a single database table but stills support clustering and embedding. Even though the API is simple, it still provides some pretty powerful features.

Give me an example!

The library itself does not have any bindings to other libraries or frameworks but a starter is provided for Spring Boot projects. Let’s use that!

Assuming a blank Spring Boot projects, you’ll need a few dependencies in your pom.xml (for Maven):

<!-- Any database will do, see https://tinyurl.com/db-scheduler-schemas

<!-- The scheduler itself, wrapped in a Spring Boot starter -->

After that add the following in src/main/resources/schema.sql. For embedded databases, it will automatically get executed.

create table if not exists scheduled_tasks (
   task_name            varchar(100),
   task_instance        varchar(100),
   task_data            blob,
   execution_time       TIMESTAMP WITH TIME ZONE,
   picked               BIT,
   picked_by            varchar(50),
   last_success         TIMESTAMP WITH TIME ZONE,
   last_failure         TIMESTAMP WITH TIME ZONE,
   consecutive_failures INT,
   last_heartbeat       TIMESTAMP WITH TIME ZONE,
   version              BIGINT,
   PRIMARY KEY (task_name, task_instance)

Go on to tweak your application.properties:

# General props

# db-scheduler (please accept the defaults or tweak before going into production :-)

Finally add a new Spring Configuration class that will provide the tasks that need to be executed. These are exposed as regular beans, so you can wire in whatever you need.

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

 Duration eagerInterval() {
   return Duration.ofMinutes(1);

 Task<Void> dumbLogging(Duration eagerInterval) {
   return Tasks
       .recurring("dumb-logging", fixedDelay(eagerInterval))
       .execute((instance, ctx) -> log.info("Hi, I log this statement every {}", eagerInterval));

Running the app should now produce log lines like:

2019-11-26 22:29:58.133  INFO 75774 --- [pool-1-thread-3] no.bekk.evenh.backgroundjobs.Jobs        : Hi, I log this statement every PT1M


As the example shows, it is really easy to get some basic background jobs up and running. db-scheduler also supports more advanced features such as scheduling one-time tasks with arbitrary data for use at execution-time or recurring tasks keeping an internal state.