Example 5 - Job Misfires
This example is designed to demonstrate concepts related to trigger misfires.
The program will perform the following actions:
Start up the Quartz Scheduler
Schedule two jobs, each job will execute every three seconds for an indefinite length of time
The jobs will take ten seconds to run (preventing the execution trigger from firing every three seconds)
Each job has different misfire instructions
The program will wait 10 minutes so that the two jobs have plenty of time to run
Shut down the scheduler
Running the Example
This example can be executed from the examples/example5 directory. There are two ways to run this example
example5.sh - A UNIX/Linux shell script
example5.bat - A Windows Batch file
The Code
The code for this example resides in the package org.quartz.examples.example5.
The code in this example is made up of the following classes:
Class Name | Description |
MisfireExample | The main program. |
StatefulDumbJob | A simple job class whose execute method takes 10 seconds to run. |
StatefulDumbJob
StatefulDumbJob is a simple job that prints its execution time and then waits for a period of time before completing. The amount of wait time is defined by the job parameter EXECUTION_DELAY. If this job parameter is not passed in, the job will default to a wait time of 5 seconds. The job also keeps its own count of how many times it has executed using a value in its JobDataMap called NUM_EXECUTIONS. Because the class has the PersistJobDataAfterExecution annotation, the execution count is preserved between each execution.
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class StatefulDumbJob implements Job {
public static final String NUM_EXECUTIONS = "NumExecutions";
public static final String EXECUTION_DELAY = "ExecutionDelay";
public StatefulDumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.err.println("---" + context.getJobDetail().getKey()
+ " executing.[" + new Date() + "]");
JobDataMap map = context.getJobDetail().getJobDataMap();
int executeCount = 0;
if (map.containsKey(NUM_EXECUTIONS)) {
executeCount = map.getInt(NUM_EXECUTIONS);
}
executeCount++;
map.put(NUM_EXECUTIONS, executeCount);
long delay = 5000l;
if (map.containsKey(EXECUTION_DELAY)) {
delay = map.getLong(EXECUTION_DELAY);
}
try {
Thread.sleep(delay);
} catch (Exception ignore) {
}
System.err.println(" -" + context.getJobDetail().getKey()
+ " complete (" + executeCount + ").");
}
}
MisfireExample
The program starts by getting an instance of the Scheduler. This is done by creating a StdSchedulerFactory and then using it to create a scheduler. This will create a simple, RAM-based scheduler, because no quartz.properties telling it to do otherwise are provided.
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
Job #1 is scheduled to run every 3 seconds indefinitely. An execution delay of 10 seconds is passed into the job:
JobDetail job = newJob(StatefulDumbJob.class)
.withIdentity("statefulJob1", "group1")
.usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L)
.build();
SimpleTrigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.startAt(startTime)
.withSchedule(simpleSchedule()
.withIntervalInSeconds(3)
.repeatForever())
.build();
sched.scheduleJob(job, trigger);
Job #2 is scheduled to run every 3 seconds indefinitely. An execution delay of 10 seconds is passed into the job:
job = newJob(StatefulDumbJob.class)
.withIdentity("statefulJob2", "group1")
.usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L)
.build();
trigger = newTrigger()
.withIdentity("trigger2", "group1")
.startAt(startTime)
.withSchedule(simpleSchedule()
.withIntervalInSeconds(3)
.repeatForever()
.withMisfireHandlingInstructionNowWithExistingCount()) // set
// misfire instruction
.build();
Note: | The trigger for job #2 is set with a misfire instruction that will cause it to reschedule with the existing repeat count. This policy forces Quartz to refire the trigger as soon as possible. Job #1 uses the default "smart" misfire policy for simple triggers, which causes the trigger to fire at it’s next normal execution time. |
The scheduler is then started.
sched.start();
To let the scheduler have an opportunity to run the job, our program sleeps for ten minutes (600 seconds)
Thread.sleep(600L * 1000L);
Finally, the program gracefully shuts down the scheduler:
sched.shutdown(true);
Note: | Passing "true" to the shutdown method tells Quartz Scheduler to wait until all jobs have completed running before returning from the method call. |