Job Scheduling in Java
Pages: 1, 2, 3, 4

Advanced Quartz

So far we have described basic Quartz features that can be a good foundation to start using it in your projects. Besides that, this library has great architecture that can fully leverage your effort.



Besides the basics provided by Quartz, the library has a great architecture that will help solve problems in your application. One of its key features is listeners: objects that are called when some event in the system occurs. There are three types of listeners: JobListeners, TriggerListeners, and SchedulerListeners.

Listeners can be particularly useful when you want a notification if something goes wrong in the system. For example, if an error occurs during report generation, an elegant way to notify the development team about it is to make a JobListener that will send an email or SMS.

A JobListener can provide more interesting functionality. Imagine a Job that has to deal with a task that is highly dependent on some system resource availability (such as a network that is not stable enough). In this case, you can make a listener that will re-trigger that job if the resource is not available when the job is executed.

Quartz can also deal with situations when some Trigger has misfired, or didn't fire because the scheduler was down. You can set a misfire instruction by using the setMisfireInstruction() method of the Trigger class. It takes the misfire instruction type for a parameter, which can have one of the following values:

  • Trigger.INSTRUCTION_NOOP: does nothing.
  • Trigger.INSTRUCTION_RE_EXECUTE_JOB: executes the job immediately.
  • Trigger.INSTRUCTION_DELETE_TRIGGER: deletes the misfired trigger.
  • Trigger.INSTRUCTION_SET_TRIGGER_COMPLETE: declares the trigger completed.
  • Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE: declares all triggers for that job completed.
  • Trigger.MISFIRE_INSTRUCTION_SMART_POLICY: chooses the best fit misfire instruction for a particular Trigger implementation.

Trigger implementations (such as CronTrigger) can define new types of misfire instructions that can be useful. You should check out the Javadocs for these classes for more information on this topic. Using the TriggerListener, you can gain more control on actions that should be used if a misfire occurs. Also, you can use it to react to trigger events, such as a trigger's firing and completion.

SchedulerListener deals with global system events, such as scheduler shutdown or the addition or removal of jobs and triggers.

Here, we will just demonstrate a simple JobListener for our report generation example. First we have to write a class to implement the JobListener interface.

package net.nighttale.scheduling;

import org.quartz.*;


public class MyJobFailedListener implements JobListener {

  public String getName() {
    return "FAILED JOB";
  }

  public void jobToBeExecuted
    (JobExecutionContext arg0) {
  }


  public void jobWasExecuted(
    JobExecutionContext context,
    JobExecutionException exception) {

    if (exception != null) {
      System.out.println(
        "Report generation error"
      );
      // TODO notify development team
    }	
  }
}

and then add the following line to the main method of our example:

sched.addGlobalJobListener(new MyJobFailedListener());

By adding this listener to the global list of scheduler job listeners, it will be called for all of the jobs. Of course, there is a way to set listeners only for a particular job. To do this, you should use Scheduler's addJobListeners() method to register the listener with the scheduler. Then add the registered listener to the job's list of listeners with JobDetail's addJobListener() method, with the listener name as a parameter (the value returned from getName() method of the listener).

sched.addJobListener(new MyJobFailedListener());
jobDetail.addJobListener("FAILED JOB");

To test if this listener really works, simply put

throw new JobExecutionException();

in the execute() method of the report generation job. After the job has been executed, the jobWasExecuted() method of our listener is executed, and the thrown exception is passed as the argument. Because the exception is not null in our case, you should expect to see the message "Report generation error" on the screen.

One final note about listeners is that one should be careful about number of listeners that is used in the system, because it could down the performance of the application.

There is one more way you can extend Quartz's features, and that is through plug-ins. Plug-ins can do practically any work you need; all you have to is to write the class implementing the org.quartz.spi.SchedulerPlugin interface. This interface defines two methods that need to be implemented -- one for initialization (which takes a Scheduler object as a parameter) and one for shutdown. Everything else is up to you. In order to make SchedulerFactory use a certain plug-in, all you have to do is to add a line in the properties file (quartz.properties) with the plug-in class and a few optional configuration parameters (which depend on the particular plug-in). There are a few plug-ins already in Quartz itself. One is the shutdownHook, which can be used to cleanly shut down the scheduler in case the JVM terminates. To use this plug-in, just add the following lines in the configuration file:

org.quartz.plugin.shutdownHook.class = 
   org.quartz.plugins.management.ShutdownHookPlugin
org.quartz.plugin.shutdownHook.cleanShutdown = true

Pages: 1, 2, 3, 4

Next Pagearrow