I would recommend an implementation like this one to recover the job after a fail:
final JobDataMap jobDataMap = jobCtx.getJobDetail().getJobDataMap();
// the keys doesn't exist on first retry
final int retries = jobDataMap.containsKey(COUNT_MAP_KEY) ? jobDataMap.getIntValue(COUNT_MAP_KEY) : 0;
// to stop after awhile
if (retries < MAX_RETRIES) {
log.warn("Retry job " + jobCtx.getJobDetail());
// increment the number of retries
jobDataMap.put(COUNT_MAP_KEY, retries + 1);
final JobDetail job = jobCtx
.getJobDetail()
.getJobBuilder()
// to track the number of retries
.withIdentity(jobCtx.getJobDetail().getKey().getName() + " - " + retries, "FailingJobsGroup")
.usingJobData(jobDataMap)
.build();
final OperableTrigger trigger = (OperableTrigger) TriggerBuilder
.newTrigger()
.forJob(job)
// trying to reduce back pressure, you can use another algorithm
.startAt(new Date(jobCtx.getFireTime().getTime() + (retries*100)))
.build();
try {
// schedule another job to avoid blocking threads
jobCtx.getScheduler().scheduleJob(job, trigger);
} catch (SchedulerException e) {
log.error("Error creating job");
throw new JobExecutionException(e);
}
}
Why?
- It will not block Quartz Workers
- It will avoid back pressure. With setRefireImmediately the job will be fired immediately and it could lead to back pressure issues