Quartz is an open-source Job scheduler that we can leverage to schedule enterprise-grade jobs. Spring boot also supports scheduling Quartz Jobs by providing the starter dependency. In this article, we will learn how to create a simple quartz scheduler along with the spring boot framework.
We will create a spring boot application with a REST API that accepts a request parameter. We will dynamically schedule the quartz job by invoking the API. Also, We will pass the request parameter to the job that prints the value on the application’s console.
The quartz scheduler also supports persisting the scheduler and job details into a database. This is an useful feature as the scheduler can handle any failure or misfire of the job.
We will also enable clustering of jobs so that the spring quartz application supports scaling without any issues.
We will use the PostgreSQL database along with spring data JPA.
Version details
- Spring boot version : 2.7.2
Table of Contents
- Using spring boot quartz dependency
- Creating a Job class
- Configuring the Quartz scheduler
- Scheduling the Job
- Testing the application
- Conclusion
Using spring boot quartz dependency
Spring boot provides the spring-boot-starter-quartz starter dependency that we can leverage to create quartz schedulers to schedule a job.
We also have the spring data jpa and postgresql dependencies, as shown below.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> </dependency>
Creating a Job class
Create a Job class as shown below.
The class implements execute() method of the Job interface, and this method is the starting point of the Quartz scheduler job.
@Slf4j public class MyMessagePrinter implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { JobDataMap jobDataMap = jobExecutionContext.getMergedJobDataMap(); String message = jobDataMap.get("message").toString(); log.info("Scheduler is printing message:: {}", message); } }
The method has a parameter of type JobExecutionContext, which is helpful in retrieving the job data and other details that we can add while scheduling the Quartz job.
In our example, we are retrieving the job data with the key message and logging the message.
Configuring the Quartz scheduler
To override the default configuration, add the below properties to the application.yml configuration file.
spring: datasource: url: jdbc:postgresql://localhost/postgres username: postgres password: mysecretpassword pool-size: 10 jpa: database-platform: org.hibernate.dialect.PostgreSQLDialect quartz: job-store-type: jdbc jdbc: initialize-schema: always properties: org: quartz: threadPool: class: org.quartz.simpl.SimpleThreadPool threadCount: 5 jobStore: class: org.springframework.scheduling.quartz.LocalDataSourceJobStore dataSource: spring.datasource driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate isClustered: true scheduler: instanceName: message-printer instanceId: AUTO
First, we are configuring the spring data source with the PostgreSQL database.
Then, we are configuring the quartz-specific configuration to support clustered and persistent jobs.
We are specifying the quartz job-store-type as jdbc. It overrides the default RAMJobStore in-memory job store.
The quartz initialize-scheme property initializes all the required database tables that quartz uses to persist the scheduler and job details.
We can also use the spring.quartz.properties configuration prefix to set quartz-specific configurations like thread pool, etc.
The quartz job store class is set to LocalDataSourceJobStore, along with the data source property, so that quartz uses the available spring data source.
We can use the isClustered flag to enable the clustering. Also, it is better to set the instanceId property value to AUTO so that the application generates a random instance ID for every new application instance.
Scheduling the Job
In this example, we will schedule the job dynamically using a REST endpoint.
If necessary, we can also define them as spring beans so that job gets scheduled during the application startup.
Create a SchedulerController.java class and a /schedule-job REST API as shown below.
@Slf4j @RestController public class SchedulerController { @Autowired private Scheduler scheduler; @GetMapping("/schedule-job") public String scheduleJob(@RequestParam("msg") String message) throws SchedulerException { JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("message", message); JobKey jobKey = new JobKey("MessagePrintingJob"); JobDetail jobDetail = JobBuilder.newJob() .withIdentity(UUID.randomUUID().toString()) .setJobData(jobDataMap) .withDescription("Simple message printing Job.") .ofType(MyMessagePrinter.class) .storeDurably() .build(); Trigger trigger = TriggerBuilder.newTrigger() .forJob(jobDetail) .startAt(Date.from(Instant.now().plus(30, ChronoUnit.SECONDS))) .withDescription("Simple message printing Job trigger.") .build(); log.info("Scheduling printing message Job with message :{}", message); scheduler.scheduleJob(jobDetail, trigger); return "Job scheduled!!"; } }
The API accepts a request parameter with the name msg. We will use the value of this parameter as job data.
The main parts of the quartz scheduler are Job, Trigger, and Scheduler.
Job
The Job contains the details about the job execution.
Every quartz job can have a unique job key. We are creating a job key with the name MessagePrintingJob.
We can use JobBuilder class to create a new job along with its properties such as durability, job identity, job data, etc.
Also, we can use the ofType() method to specify the job class to invoke during job execution. We created this class in the initial part of the article.
Trigger
Once the JobDetail is ready, we need to configure the Trigger. Trigger specifies when a job is triggered.
Quarts provides TriggerBuilder class that we can use to create an instance of the trigger. Quartz supports different triggers like CRON triggers, simple triggers, etc.
Scheduler
The Scheduler is responsible for scheduling the Job with provided job details and trigger information.
We are using spring boot’s auto-configured Scheduler instance to schedule our message printing job.
Testing the application
Run the application we should see the scheduler initialized message as shown below. Scheduler supports persistence and clustering.

The application also initializes the database tables required for the quartz scheduler.

Invoke the API, and we can observe that the job is scheduled to print the requested message.

Once the request is received, the scheduler schedules the job to print the message after 30 seconds.

The job details also get persisted in the database, as shown below.



Conclusion
In this article, we learned how to schedule the job using the Quartz scheduler and spring boot.
We also learned how to enable clustering and job persistence for quartz schedulers.
Example code is available on Github.