Quartz Scheduler Properties Example
In this is article, we will see how to configure Quartz Scheduler using properties file. The properties file will be used by the scheduler factory to instantiate a scheduler.
The properties file can be used to inject the actual concrete classes of the specified classes for example the JobStore, ThreadPool, and other SPI classes etc.
Before we start with the example, I will brief you about the quartz and the setup involved.
1. What is Quartz?
Quartz is a Java open source job-scheduling system capable of scheduling and executing jobs. In this example, we use the latest stable Quartz available which is version 2.2.1. You can download Quartz from http://quartz-scheduler.org/downloads
2. Quartz Setup
In this example, we will use Maven as the build tool so all you need to do is add the below dependency to pom.xml which looks like below.
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javacodegeeks.camel</groupId> <artifactId>camelHelloWorld</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency> </dependencies> </project>
3. Why do we need quartz.properties file?
The properties file can be used to inject the actual concrete classes of the specified classes for example the JobStore, ThreadPool, and other SPI classes etc. Once the instance is created, its own properties will be set using the additional properties specified for them in the config file which will be used to invoke the corresponding setter method. For example if the properties file contains the property ‘org.quartz.jobStore.myProp = 10’ then after the JobStore class has been instantiated, the method ‘setMyProp()’ will be called on it. Type conversion to primitive Java types (int, long, float, double, boolean, and String) are performed before calling the property’s setter method.
4. Where is quartz.properties located?
One can specify the properties in the default file called “quartz.properties” which is assumed to be located current working directory. If it is not found there then “quartz.properties” file be searched in the org/quartz package. If you wish to use a file other than the default one, you must define the system property ‘org.quartz.properties’ to point to the file you want.
5. Referring to other properties
One property can reference another property’s value by specifying a value following the convention of “$@other.property.name”, for example, to reference the scheduler’s instance name as the value for some other property, you would use “$@org.quartz.scheduler.instanceName”.
6. Sample quartz.properties file
So how does a quartz.properties
file look like. Here is a sample properties file.
org.quartz.scheduler.instanceName=JavacodeGeeksScheduler org.quartz.scheduler.instanceId=99199 org.quartz.scheduler.rmi.export=false org.quartz.scheduler.rmi.proxy=false org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount=3 org.quartz.context.key.QuartzTopic=QuartzPorperties
7. Some of the main Quartz Properties
Let’s go through each available property.
- org.quartz.scheduler.instanceName – You can specify any value you want, scheduler won’t do any kind of validation. It is used for the client code to distinguish schedulers when it relies on multiple schedulers withing the same program. This is of great help, if you are using the clustering features and you want to rely on a logical scheduler.
- org.quartz.scheduler.instanceId – This maintains the uniqueness for all schedulers working within a cluster. The ID can be any value. There are couple of IDs which are special to the scheduler. They are the value
AUTO
andSYS_PROP
. If it isAUTO
quartz will automatically generate an ID for you. If itSYS_PROP
, it means it is a system property and the value comes from the system propertyorg.quartz.scheduler.instanceId
. - org.quartz.scheduler.instanceIdGenerator.class – This is used only if
org.quartz.scheduler.instanceId
is set toAUTO
. By default, quartz generates the ID for you using its internal generator classorg.quartz.simpl.SimpleInstanceIdGenerator
. If you want to use a different generator, then the class name should be mentioned here. Quartz provide few more generator classes, you can write onf of your own by implementingInstanceIdGenerator
. - org.quartz.scheduler.threadName – This represents name of the Quartz java thread. If this property is not specified, the thread will derive its name from the scheduler’s name.
- org.quartz.scheduler.makeSchedulerThreadDaemon – This is a boolean value
true
orfalse
that specifies whether the main thread of the scheduler should be a daemon thread or not. - org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer – This is a boolean value
true
orfalse
that specifies whether the threads spawned by Quartz will inherit the context ClassLoader of the initializing thread. - org.quartz.scheduler.idleWaitTime – This is the wait time in milliseconds that the scheduler will use to wait before it starts to re-query for an available trigger when the scheduler is otherwise idle.
- org.quartz.scheduler.dbFailureRetryInterval – This will be used by the scheduler when it has lost the connection to JobStore database. This is the wait time of the scheduler before it tries re-connecting to the JobStore.
- org.quartz.scheduler.classLoadHelper.class – This is the helper class that Quartz uses to load a class or resource. By default it uses
org.quartz.simpl.CascadingClassLoadHelper
which in turn uses every otherClassLoadHelper
class until one works. - org.quartz.scheduler.jobFactory.class – The is class name of the
JobFactory
to use which is responsible for producing instances of Job Classes. - org.quartz.context.key.SOME_KEY – It represent a name-value pair that will be placed into the “scheduler context” as strings. For example,
org.quartz.context.key.QuartzTopic = QuartzProperties
. - org.quartz.scheduler.userTransactionURL – This is the JNDI URL at which Quartz can locate the Application Server’s UserTransaction manager, the default value is
java:comp/UserTransaction
- org.quartz.scheduler.wrapJobExecutionInUserTransaction – Should be set to
true
if you want your job to be executed within a a UserTransaction. - org.quartz.scheduler.skipUpdateCheck – This is used to log extra information in log in case an updated version of Quartz is available for download. It will decide Whether or not to skip running a quick web request to determine if there is an updated version of Quartz available for download./li>
- org.quartz.scheduler.batchTriggerAcquisitionMaxCount – The maximum number of triggers that a scheduler node is allowed to acquire (for firing) at once. Default value is 1.
- org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow – The amount of time in milliseconds that a trigger is allowed to be acquired and fired ahead of its scheduled fire time. Defaults to 0.
8. ThreadPool Properties
org.quartz.threadPool.class
– Name of the ThreadPool implementation that Quartz will use. In our example we will useorg.quartz.simpl.SimpleThreadPool
.org.quartz.threadPool.threadCount
– Number of threads available for concurrent execution of jobs. This is be any positive integer, ideally between 1 and 100.org.quartz.threadPool.threadPriority
– This can be any int between Thread.MIN_PRIORITY (which is 1) and Thread.MAX_PRIORITY (which is 10). The default is Thread.NORM_PRIORITY (5).
One can further specify properties based on the thread pool class chosen to set the thread pools’s properties.
9. Trigger Listener Properties
We can also configure trigger and job listeners through the configuration file consists of a property where we will specify the listener class name, and any other properties to be set on the instance. The class must have a no-arg constructor, and the properties are set reflectively.
org.quartz.triggerListener.NAME.class
– Trigger listener class name, should implementTriggerListener
org.quartz.triggerListener.NAME.propName
– Trigger listener’s property key and vale. There should be corresponding setter method.
10. Job Listener Properties
Just like trigger listener properties, we also have properties for job listener.
org.quartz.jobListener.NAME.class
– Job listener class name, should implementJobListener
org.quartz.jobListener.NAME.propName
– Job listener’s property key and vale. There should be corresponding setter method.
11. Example of Quartz Scheduler Properties
Let’s now combine some of the properties that we went through into an example.
Create your own Trigger listener.
MyTriggerListener:
package com.javacodegeeks.quartz; import org.quartz.JobExecutionContext; import org.quartz.Trigger; import org.quartz.Trigger.CompletedExecutionInstruction; import org.quartz.TriggerListener; public class MyTriggerListener implements TriggerListener { private String someProp; public String getName() { return "MyTrigger: " + someProp; } public void triggerFired(Trigger trigger, JobExecutionContext context) { System.out.println("Trigger fired: " + trigger.getDescription()); } public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) { return false; } public void triggerMisfired(Trigger trigger) { } public void triggerComplete(Trigger trigger, JobExecutionContext context, CompletedExecutionInstruction triggerInstructionCode) { System.out.println("Trigger completed: " + trigger.getDescription()); } public String getSomeProp() { return someProp; } public void setSomeProp(String someProp) { this.someProp = someProp; } }
and a job listener.
MyJobListener:
package com.javacodegeeks.quartz; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobListener; public class MyJobListener implements JobListener { private String someProp; public String getSomeProp() { return someProp; } public void setSomeProp(String someProp) { this.someProp = someProp; } public String getName() { return "MyJobListener: " + someProp; } public void jobToBeExecuted(JobExecutionContext context) { System.out.println("Job to be exected: " + context.getFireInstanceId() + ", job listener: " + getName()); } public void jobExecutionVetoed(JobExecutionContext context) { } public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { System.out.println("Job was exected: " + context.getFireInstanceId() + ", job listener: " + getName()); } }
Let’s now define our job
MyJob:
package com.javacodegeeks.quartz; import org.quartz.Job; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; public class MyJob implements Job { private static int count; public void execute(JobExecutionContext jobContext) throws JobExecutionException { System.out.println("--------------------------------------------------------------------"); System.out.println("MyJob start: " + jobContext.getFireTime()); JobDetail jobDetail = jobContext.getJobDetail(); System.out.println("Example name is: " + jobDetail.getJobDataMap().getString("example")); System.out.println("MyJob end: " + jobContext.getJobRunTime() + ", key: " + jobDetail.getKey()); System.out.println("MyJob next scheduled time: " + jobContext.getNextFireTime()); System.out.println("--------------------------------------------------------------------"); System.out.println("Job's thread name is: " + Thread.currentThread().getName()); ILatch latch = (ILatch) jobDetail.getJobDataMap().get("latch"); latch.countDown(); count++; System.out.println("Job count " + count); if (count == 2) { throw new RuntimeException("Some RuntimeException!"); } if (count == 4) { throw new JobExecutionException("Some JobExecutionException!"); } } }
We want to make sure that the scheduler shuts down automatically after a specified runs so we have a latch which we count down as and when a job is run.
ILatch:
package com.javacodegeeks.quartz; public interface ILatch { void countDown(); }
Here is our main example.
QuartzSchedulerPropertiesExample:
package com.javacodegeeks.quartz; import java.util.concurrent.CountDownLatch; import org.quartz.JobBuilder; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.SimpleScheduleBuilder; import org.quartz.Trigger; import org.quartz.TriggerBuilder; public class QuartzSchedulerPropertiesExample implements ILatch { private int repeatCount = 3; private CountDownLatch latch = new CountDownLatch(repeatCount + 1); public static void main(String[] args) throws Exception { QuartzSchedulerPropertiesExample quartzSchedulerExample = new QuartzSchedulerPropertiesExample(); quartzSchedulerExample.fireJob(); } public void fireJob() throws SchedulerException, InterruptedException { SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory(); Scheduler scheduler = schedFact.getScheduler(); System.out.println("Scheduler name is: " + scheduler.getSchedulerName()); System.out.println("Scheduler instance ID is: " + scheduler.getSchedulerInstanceId()); System.out.println("Scheduler context's value for key QuartzTopic is " + scheduler.getContext().getString("QuartzTopic")); scheduler.start(); // define the job and tie it to our HelloJob class JobBuilder jobBuilder = JobBuilder.newJob(MyJob.class); JobDataMap data = new JobDataMap(); data.put("latch", this); JobDetail jobDetail = jobBuilder.usingJobData("example", "com.javacodegeeks.quartz.QuartzSchedulerExample") .usingJobData(data) .withIdentity("myJob", "group1") .build(); // Trigger the job to run now, and then every 40 seconds Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withRepeatCount(repeatCount) .withIntervalInSeconds(2)) .withDescription("MyTrigger") .build(); // Tell quartz to schedule the job using our trigger scheduler.scheduleJob(jobDetail, trigger); latch.await(); System.out.println("All triggers executed. Shutdown scheduler"); scheduler.shutdown(); } public void countDown() { latch.countDown(); } }
Here is our complete quartz properties file.
quartz.properties:
org.quartz.scheduler.instanceName=JavacodeGeeksScheduler org.quartz.scheduler.instanceId=99199 org.quartz.scheduler.rmi.export=false org.quartz.scheduler.rmi.proxy=false org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount=3 org.quartz.context.key.QuartzTopic=QuartzPorperties org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore org.quartz.triggerListener.NAME.class=com.javacodegeeks.quartz.MyTriggerListener org.quartz.triggerListener.NAME.someProp=SomeTriggerValue org.quartz.jobListener.NAME.class= com.javacodegeeks.quartz.MyJobListener org.quartz.jobListener.NAME.someProp=SomeJobValue
You can see from the output that the Quartz Scheduler was able to pick up the scheduler name, its instance ID, trigger listener, job listener, the key value properties of the scheduler context as well as the other listener properties.
Output:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. Scheduler name is: JavacodeGeeksScheduler Scheduler instance ID is: 99199 Scheduler context's value for key QuartzTopic is QuartzPorperties Trigger fired: MyTrigger Job to be exected: 1443678721202, job listener: MyJobListener: SomeJobValue -------------------------------------------------------------------- MyJob start: Thu Oct 01 11:22:01 IST 2015 Example name is: com.javacodegeeks.quartz.QuartzSchedulerExample MyJob end: -1, key: group1.myJob MyJob next scheduled time: Thu Oct 01 11:22:03 IST 2015 -------------------------------------------------------------------- Job's thread name is: JavacodeGeeksScheduler_Worker-1 Job count 1 Job was exected: 1443678721202, job listener: MyJobListener: SomeJobValue Trigger completed: MyTrigger Trigger fired: MyTrigger Job to be exected: 1443678721203, job listener: MyJobListener: SomeJobValue -------------------------------------------------------------------- MyJob start: Thu Oct 01 11:22:03 IST 2015 Example name is: com.javacodegeeks.quartz.QuartzSchedulerExample MyJob end: -1, key: group1.myJob MyJob next scheduled time: Thu Oct 01 11:22:05 IST 2015 -------------------------------------------------------------------- Job's thread name is: JavacodeGeeksScheduler_Worker-2 Job count 2 Job was exected: 1443678721203, job listener: MyJobListener: SomeJobValue Trigger completed: MyTrigger Trigger fired: MyTrigger Job to be exected: 1443678721204, job listener: MyJobListener: SomeJobValue -------------------------------------------------------------------- MyJob start: Thu Oct 01 11:22:05 IST 2015 Example name is: com.javacodegeeks.quartz.QuartzSchedulerExample MyJob end: -1, key: group1.myJob MyJob next scheduled time: Thu Oct 01 11:22:07 IST 2015 -------------------------------------------------------------------- Job's thread name is: JavacodeGeeksScheduler_Worker-3 Job count 3 Job was exected: 1443678721204, job listener: MyJobListener: SomeJobValue Trigger completed: MyTrigger Trigger fired: MyTrigger Job to be exected: 1443678721205, job listener: MyJobListener: SomeJobValue -------------------------------------------------------------------- MyJob start: Thu Oct 01 11:22:07 IST 2015 Example name is: com.javacodegeeks.quartz.QuartzSchedulerExample MyJob end: -1, key: group1.myJob MyJob next scheduled time: null -------------------------------------------------------------------- Job's thread name is: JavacodeGeeksScheduler_Worker-1 Job count 4 All triggers executed. Shutdown scheduler Job was exected: 1443678721205, job listener: MyJobListener: SomeJobValue Trigger completed: MyTrigger
12. Download the Eclipse Project
This was an example about Quartz Scheduler Properties.
You can download the full source code of this example here: quartzSchedulerPropertiesExample.zip
I am thinking a seperate quartz.properties is needed, if you are extensively using Quartz and with a separate quartz activities persistence database instead of using application database. e.g. for Mysql schemas it can be: application database schema – MyAppDb quartz database schema – MyAppQuartzDB However, it is not mentioned how to make Quartz look for quartz.properties file. Is it a config in application.properties? Or Is it the usual @Configuration annotated class route with the @Bean annotated method: e.g. @Bean public SchedulerFactoryBean configureQuartzScheduler() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setConfigLocation(new ClassPathResource(“/quartz.properties”)); return schedulerFactoryBean; } Also, in case of a Spring Boot… Read more »