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):

< dependency > < groupId > org.hsqldb </ groupId > < artifactId > hsqldb </ artifactId > < scope > runtime </ scope > </ dependency > < dependency > < groupId > com.github.kagkarlsson </ groupId > < artifactId > db-scheduler-spring-boot-starter </ artifactId > < version > 6.2 </ version > </ dependency >

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 spring.application.name=background-jobs # db-scheduler (please accept the defaults or tweak before going into production :-) db-scheduler.threads=3 db-scheduler.polling-interval=5s

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.

@Configuration class Jobs { private static final Logger log = LoggerFactory . getLogger ( Jobs . class ) ; @Bean Duration eagerInterval ( ) { return Duration . ofMinutes ( 1 ) ; } @Bean 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

Summary

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.