Quartz Scheduler – Introduction
Quartz Scheduler is an open-source job scheduling library that can work with any Java application to create simple or complex CRON schedules for executing a vast amount of jobs. The Quartz Scheduler also includes many enterprise-class features, such as support for JTA transactions and clustering.
To simply put, If your application has tasks that need to occur at given moments in time, or if your application has recurring maintenance jobs then Quartz may be your ideal solution. Quartz scheduler provides out of the box job scheduling via java API to create CRON schedules and Simple recurrence schedules and even single run schedules.
Download and Install Quartz libraries
To set up a quartz scheduler in your plain java application, you need to download the latest stable release distribution. Locate and add the quartz-***.jar available under lib directory to your application classpath. Also, quartz depends on a couple of libraries that are also available as part of the distribution. Make sure you add them as well.
Alternatively, you could use maven to manage quartz libraries for you. Just add the following dependency to your maven project.
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<!-- Optional Logging dependency : If you don't see quartz logs in your application add this -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
Code language: HTML, XML (xml)
I recommend the maven based approach as it automatically fetches the needed jars and adds them to application classpath.
Create a quartz.properties file
By Default, the Quartz scheduler doesn’t require a properties file to work. However, you would need one if you want to override the default config. To configure the scheduler, you should first add a quartz.properties
file to your classpath. For example, Take a look at this configuration that uses an in-memory implementation.
org.quartz.scheduler.instanceName = custom-scheduler
org.quartz.threadPool.threadCount = 10
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
Code language: Properties (properties)
In the above example, We named our scheduler, set the thread count as 10 and let quartz data be stored in the RAM.
Sample Application that uses Quartz Scheduler
To test the setup, Let’s write a simple Java Application that creates a scheduler.
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzApplication {
public static void main(String[] args) throws SchedulerException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
scheduler.shutdown();
}
}
Code language: Java (java)
When you run this program, You would see the following output showing the quartz scheduler starting and immediately shutting down as there are no jobs in the scheduler.
Here the start
and stop
methods are important. They are the entry and exit points of the Quartz scheduler instance respectively. There is also a standby
method that temporarily makes the scheduler from running new jobs. You should invoke this method as shown here.
scheduler.standby();
Code language: Java (java)
By default, the Scheduler instantiates in standby mode. The scheduler will begin firing jobs only after the start method is called.
Also, The Scheduler cannot be restarted after shutdown() has been called.
Understand the Quartz Scheduler API
There are few main classes interfaces you should get familiar with. They are,
org.quartz.Job | Represents a `job` to be executed in the scheduler. |
org.quartz.JobDetail | JobDetail provides information to create a job instance. |
org.quartz.Trigger | Represents a condition in which a job would start. It could either be a fixed timestamp or a CRON expression. |
org.quartz.JobBuilder | As the name suggests, it builds a job detail for a given Job implementation. |
org.quartz.TriggerBuilder | This class is used to create simple and complex schedules for job detail. |
Write a Job Class
As we saw earlier, The first step at scheduling a piece of code is to create a job for it. For example, Here is a HelloWorldJob
that prints data from job detail.
package com.springhow.examples.quartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorldJob implements Job {
private static final Logger logger = LoggerFactory.getLogger(HelloWorldJob.class);
@Override
public void execute(JobExecutionContext context) {
String who = context.getJobDetail().getJobDataMap().getString("who");
logger.info("Hello {}!", who);
}
}
Code language: Java (java)
Here, The job has access to the JobExecutionContext
which all necessary metadata about the current run.
Create a JobDetail
Next, You should create an appropriate job details to submit to scheduler. You can do this by using the JobBuilder we have seen earlier.
JobDetail jobDetail = JobBuilder.newJob(HelloWorldJob.class)
.withIdentity("my-first-job")
.usingJobData("who","World!")
.build();
Code language: Java (java)
As you see, The example creates a job with the name “my-first-job” and uses the HelloWorldJob
as job template. A, We are passing job data so that we can access them through the context in the execute method of the job.
Also note that when identity is not specified, the quartz scheduler auto generates an UUID. You could also provide a group name for the job in the withIdentity
method.
Create a Trigger
For a job to execute, the scheduler should know when to invoke them. This information comes from Trigger objects. Triggers are either simple or repeating(CRON) schedules in the quartz scheduler. For example, We could create a simple recurring schedule as shown below.
Trigger trigger = TriggerBuilder.<em>newTrigger</em>()
.withIdentity("my-first-trigger")
.startNow()
.withSchedule(SimpleScheduleBuilder.<em>simpleSchedule</em>()
.withIntervalInSeconds(3)
.repeatForever())
.build();
Code language: Java (java)
Cron Trigger
You could also create a CRON trigger as shown in this snippet. For example, the below trigger fires every even minute, between 9AM and 6PM on all week days.
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("my-cron-trigger")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 9-18 * * MON-FRI"))
.build();
Code language: Java (java)
Schedule The Job with Trigger
Finally, You need to let the quartz scheduler know which job to trigger when. In this case, We are scheduling “my-first-job” using the “my-first-trigger”.
As you see, The jobs get called every three seconds as we configured in the simple trigger.
Remove a Quartz job from the scheduler
Sometimes, you might want to remove the quartz job from the scheduler. You can do this in two ways.
Remove the trigger associated with a job.
scheduler.unscheduleJob(new TriggerKey("my-first-trigger"));
Code language: Java (java)
Note that there may be more than one triggers for a given job. For example, A job in quartz scheduler may contain one simple trigger that runs every day and another cron trigger that runs only on weekends.
Remove the job itself from the scheduler by deleting it.
scheduler.deleteJob(new JobKey("my-first-job"));
Code language: Java (java)
Note that this approach deletes the hob as well as the triggers associated with it. This way, you don’t have to delete the triggers separately.
Listing jobs and triggers
The quartz java API allows developers to query the jobs and triggers within a given scheduler instance. For instance, you could query all jobs within a scheduler as shown in this snippet.
for(String group: scheduler.getJobGroupNames()) {
for(JobKey jobKey : scheduler.getJobKeys(groupEquals(group))) {
logger.info(jobKey);
}
}
Code language: Java (java)
Similarly, We can also query all triggers within a scheduler. Just use the getTriggerGroupNames
and getTriggerKeys
instead.
You could also lookup all the triggers associated with a given job.
List<Trigger> jobTriggers = scheduler.getTriggersOfJob(jobKey("my-first-trigger"));
Code language: Java (java)
There are many useful methods under the
Scheduler
interface and the JobBuilder/TriggerBuilder classes. Make sure you explore them for better understanding.
Summary
To summarize, Quartz scheduler is a one stop tool for all of your scheduling needs in a java application. Some of its features include,
- Quartz can embed into any java application as it is written in pure java.
- By providing a crontab-like approach, Quartz can handle complex recurrence schedules. With multiple triggers for the same job, The possibilities are limitless.
- Job definitions are done via java classes and their respective quartz API methods. This makes the library more developer-friendly.
- The JobStore interface allows job information to be persisted. A most common approach is to use JDBCJobStore to keep the job data available between application restarts. The API also provides the developers with the option to provide a custom JobStore.
- The library is JTA(Java Transaction API) compatible.
- The quartz scheduler can run in cluster mode and can be load balanced. This makes the library scalable.
- With the help of listeners and plugins, job failures can be handled accordingly.
You can find all the above examples in the quartz-example github repository.