Quartz Scheduled Jobs – v1.5.2

Java, XML, and cron driven scheduling made easy.

Projects here and there often need some kind of mechanism to schedule jobs at odd hours, or intervals. Quartz is a robust, flexible tool you can use to accomplish simple to complex job scheduling. There are a number of ways to use/configure quartz, but I’ve grown accustomed to using it with an xml based configuration. There are a few things we need to set up unfortunately, so there is a certain amount of plumbing we need to work out, but once that infrastructure is set up, its much less work to set up additional jobs.

web.xml

Originally, I went on about writing a custom quartz servlet to initialize the engine, but theres an even easier way to set this up as Sibz has pointed out in a comment:

<servlet>
	<servlet-name>
		QuartzInitializer
	</servlet-name>
	<display-name>
		Quartz Initializer Servlet
	</display-name>
	<servlet-class>
		org.quartz.ee.servlet.QuartzInitializerServlet
	</servlet-class>
	<load-on-startup>1</load-on-startup>
	<init-param>
		<param-name>config-file</param-name>
		<param-value>/some/path/my_quartz.properties</param-value>
	</init-param>
	<init-param>
		<param-name>shutdown-on-unload</param-name>
		<param-value>true</param-value>
	</init-param>
	<init-param>
		<param-name>start-scheduler-on-load</param-name>
		<param-value>true</param-value>
	</init-param>
</servlet>

This xml snippet was blatanlty hijacked from quartz’ documentation page. As you might have guessed, this xml configuration goes in your web.xml. No need to write your own initializer servlet, just plug and play.

We’ll need to add 2 property files. The one that fine tunes the engine in our example is quartz.properties..

quartz.properties

If you noticed in the web.xml (the init param named “config-file” is set to the path <param-value>/some/path/my_quartz.properties</param-value>), we load up a properties file that configures the quartz engine.

org.quartz.plugin.jobInitializer.class=org.quartz.plugins.xml.JobInitializationPlugin
org.quartz.plugin.jobInitializer.fileNames = quartz-config.xml
org.quartz.plugin.jobInitializer.overWriteExistingJobs = true
org.quartz.plugin.jobInitializer.failOnFileNotFound =true

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool 
org.quartz.threadPool.threadCount = 5 
org.quartz.threadPool.threadPriority = 5

The first half of the settings is pretty straight forward, but the second half is all about tuning. Setting a class other than SimpleThreadPool means you’ve written your own implementation for quartz thread management. You probably really know what you’re doing and you can stop reading. Threadcount controls the number of quartz threads dedicated to the engine. One is plenty for a job that fires off once or a few times a day. If you plan on running thousands a day, with heavy loads you’ll want something like 50 threads and up towards about 100. Threadpriority 5 means normal priority, while priority 1 is highest priority. For the most part, 5 is plenty, if you have cpu intensive processing going on, you can tune this to make sure your jobs fire off when they’re supposed

The second file we need to set up is the xml that configures your quartz job…

quartz-config.xml

<quartz>
    <job>
        <job-detail>
            <name>scheduler</name>
            <group>schedulers</group>
            <description>schedule a nightly job</description>
            <job-class>com.examples.quartz.Scheduler</job-class>
            <volatility>false</volatility>
            <durability>false</durability>
            <recover>false</recover>
			<job-data-map>
				<entry>
					<key>username</key>
					<value>someUser</value>
				</entry>
				<entry>
					<key>password</key>
					<value>somePassword</value>
				</entry>
			</job-data-map>            
        </job-detail>
        <trigger>
            <cron>
                <name>scheduler-trigger</name>
                <group>scheduler-triggers</group>
                <job-name>scheduler</job-name>
                <job-group>schedulers</job-group>
                <cron-expression>0 0/5 * * * ?</cron-expression>
            </cron>
        </trigger>
    </job>
</quartz>

This file is made up of two main sections. Job-Detail configures the job’s metadata, while trigger defines the configuration and cron expression that fires off the job. Stuff like the name, and mappings needed to configure the matching trigger, or the xml parser will complain. Parameters can be added in job-data-map and passed into the job-class for processing. Which brings us to the last item of business: THE JOB IMPLEMENTATION CLASS!!!

Scheduler.java

Scheduler is the job implementing class that defines the unit of work preformed by the quartz job. JobExecutionContext contains all the job metadata defined in the configuring xml, and the data map is the object that contains all the name/value pairs listed in the xml we just wrote up. Here’s the full class:

package com.examples.quartz;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class Scheduler implements Job {
    
	protected static final Log log = LogFactory.getLog(Scheduler.class);

	public void execute(JobExecutionContext jobContext) 
		throws JobExecutionException {

		log.info("entering the quartz config");

		JobDataMap map = jobContext.getJobDetail().getJobDataMap();
		String username = (String) map.get("username");
		String password = (String) map.get("password");

		log.info("mapped data: " + username + "/" + password);
	}

}

.. And that’s all there is to setting up a quartz jobs. If we want to add additional quartz jobs, all we would need to do is add another job node in our quartz-config.xml and write another job interface implementing class. The rest pretty much stays the same, since all the heavy lifting has been done.

Comments (7)

  1. 6:36 AM, February 5, 2010Marc  / Reply

    Dude. You guys so need Spring.

    • 10:14 AM, February 5, 2010Ant  / Reply

      Ah yea, spring’s definately sexy with its support for TimerTasks , and easier quartz configs. We’re using spring mvc in one of the newer projects, but it’s hard to justify a major refactor like that on the existing projects. Something I’ve been trying to get around to comparing is how ejb3 Timers stack up vs quartz. I like how you can set dedicated threads in quartz, but in ejb3 timers you give that up afaik and let the container handle it.

  2. 8:30 AM, February 9, 2010steve  / Reply

    Quartz has moved to http://www.quartz-scheduler.com. Not at Open Symphony anymore.

    • 8:43 AM, February 9, 2010Ant  / Reply

      You’re right – I’ll update. My bad!

  3. 8:47 AM, February 9, 2010steve  / Reply

    Thanks! And thanks for the blog!

  4. 4:33 PM, February 11, 2010Sibz  / Reply

    I have used quartz recently in one of my projects that I was working on. And what I did was to use the org.quartz.ee.servlet.QuartzInitializerServlet that came by default with the quartz jar file instead of writing a custom initializer servlet and added that entry to the web.xml. As long as “quartz.properties is the classpath” it would get picked up. FYI

  5. 5:02 PM, February 11, 2010Ant  / Reply

    Sibz – I didn’t know about that Quartz servlet, I’ve updated the article with the new info. Thanks for the tip!

Leave a Reply

Allowed Tags - You may use these HTML tags and attributes in your comment.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>