Volatility, Durability, and Recoverability
All three of these attributes are similar in that they affect the runtime behavior of a job. Each one is discussed in turn.
Job Volatility
A volatile job is one that is not persisted between program shutdowns. A job is set to be volatile by calling the setVolatility(true) method on the JobDetail.
The default value for job volatility is false.
Job Durability
A durable job is one that should remain in the JobStore, even if there are no longer any triggers that can fire for the job. Let's say that you set up a single-fire trigger that fires and is therefore moved to the STATE_COMPLETE state. No more firing times exist, but the trigger was scheduled to execute only once. The job that this trigger pointed to is now orphaned because it no longer has any triggers associated with it.
If you set a job to be durable, it will not be removed from the JobStore when it becomes orphaned. This keeps it available for further scheduling whenever your program decides to add another trigger for it. If the setDurability(false) method was invoked on the JobDetail, the job would be removed from the JobStore when all triggers have fired. The default value for durability is false. Hence, the default behavior of jobs and triggers is to be automatically removed from the JobStorethe trigger when it completes all its firing and the job when it has no associated triggers.
Job Recoverability
When the Scheduler experiences an unexpected shutdown and a job is executing, a recoverable job is re-executed when the Scheduler is restarted. The job starts executing again right from the beginning. The Scheduler has no way of knowing where the job was during execution when the program was stopped and, therefore, must start all over again.
To set a job to be recoverable, use the following method:
public void setRequestsRecovery(boolean shouldRecover);
By default, the value is set to false and the Scheduler does not try to recover the jobs.
Removing Jobs from the Scheduler
You can remove a job that has been scheduled in several ways. One way is to remove all the triggers associated with the job; if the job is durable, it will be removed from the Scheduler. An easier way is just to remove the job directly. You can use the deleteJob() method to do this:
public boolean deleteJob(String jobName, String groupName) throws SchedulerException;
Interrupting Jobs
It's sometimes necessary to be able to interrupt a job, especially if it takes a long time to execute. For example, suppose you have a job that takes an hour to run, and you realize five minutes into the job that it's going to need to run again because of some uncontrollable error. You might as well interrupt the job, fix the problem, and then rerun it.
Quartz includes an interface called org.quartz.InterruptableJob that extends the normal job interface and offers an interrupt() method:
public void interrupt() throws UnableToInterruptJobException;
You can call the interrupt() method on the Scheduler by providing the name of the job and the group that was used when the job was scheduled:
public boolean interrupt(SchedulingContext ctxt, String jobName, String groupName) throws UnableToInterruptJobException;
Listing 4.8 shows an example InterruptableJob called CheckForInterruptJob.
The Scheduler will invoke the interrupt() method on your job. It's up to you and your job to determine how to interrupt the job. Although there are several acceptable approaches, Listing 4.8 provides one of the more common. The Quartz framework can signal to a job that an interrupt has been requested for it, but here you have control over the job and, therefore, are responsible for the approach.
Listing 4.8. An InterruptableJob Can Be Used to Determine Whether interrupt() has Been Called on the Scheduler
public class CheckForInterruptJob implements InterruptableJob { static Log logger = LogFactory.getLog(CheckForInterruptJob.class); private boolean jobInterrupted = false; private int counter = 5; private boolean jobFinished = false; public void interrupt() throws UnableToInterruptJobException { jobInterrupted = true; } public void execute(JobExecutionContext context) throws JobExecutionException { while (!jobInterrupted && !jobFinished) { // Perform a small amount of processing logger.info("Processing the job"); counter; if (counter <= 0) { jobFinished = true; } // Sleep and wait for 3 seconds try { Thread.sleep(3000); } catch (InterruptedException e) { // do nothing } } if (jobFinished) { logger.info("Job finished without interrupt"); } else if (jobInterrupted) { logger.info("Job was interrupted"); } } } |
Jobs Provided by the Framework
The Quartz framework provides several jobs that you can use within your applications with little work. Table 4.1 lists the jobs and their usage.
Job Class |
Job Usage |
---|---|
org.quartz.jobs.FileScanJob |
A job that checks for changes to a specified file and then informs a listener that the file has changed. |
org.quartz.jobs.FileScanListener |
A listener that tells FileScanJob when a file has been modified. |
org.quartz.jobs.NativeJob |
A job that is used for executing native programs (such as .exe files under Windows). |
org.quartz.jobs.NoOpJob |
A job that doesn't do anything but that might be useful for testing listeners. Some users even use this just to cause a listener to run. |
org.quartz.jobs.ee.mail.SendMailJob |
A job that sends an e-mail using the JavaMail API. |
org.quartz.jobs.ee.jmx.JMXInvokerJob |
A job that invokes a method on a JMX bean. |
org.quartz.jobs.ee.ejb.EJBInvokerJob |
A job that invokes a method on an EJB. |