Sunday, May 10, 2015

Avoiding concurrency issues with Quartz Scheduler

If you're using Quartz Scheduler and CronTriggers, there's a reasonable chance that your Job's execution time might occasionally take longer than your Schedule Triggers.

What happens then?
Default behavior for Quartz Scheduler is to fire the subsequent Triggers even if the previous jobs haven't finished. The problem is that frequently that can cause unpredictable racing conditions and concurrency issues.

To fix that, Quartz offers two solutions:


Both these solutions(StatefulJob has been deprecated on Quartz 2.x) will tell the scheduler that this Job class should only have one instance running at a time.
Again, another question comes up. What happens when a Trigger is fired and intercepted because there's an ongoing previous execution? That's when Misfire Instructions come in play. First, set a misfire threshold in the properties, which will tell the scheduler how long to wait before considering a job trigger as a misfire:


#This property decides how long does the scheduler waits before considering the sebsequent jobs as misfired (default is 60000 millis)
org.quartz.jobStore.misfireThreshold=60000


Second, when instantiating the job Trigger, we've an option for setting a Misfire Instruction to decide what to do on each case:

Choose the most appropriate setting for your trigger to ensure the expected behaviour. To conclude, a setup suggestion for blocking concurrent execution on a job:
  1. Annotate the job with @DisallowConcurrentExecution
  2. Set the org.quartz.jobStore.misfireThreshold=1 so that a single millis of lateness declares the trigger as a misfire if there's a previous job ongoing
  3. Set the trigger misfire instruction to MISFIRE_INSTRUCTION_DO_NOTHING. This will simply make it abort current execution and schedule itself for next trigger execution.
trigger.setMisfireInstruction(
CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);

Sample Code: https://github.com/eduardohl/quartz-boiler

Quartz Boilerplate (Spring 4) - Running Jobs with Java

I've recently had to (yet again) deal with Quartz Jobs. I don't really like the framework, but it seems that it's the best option for many job scheduling tasks. I've searched a little bit but apparently the only framework that does the job better is called Obsidian, but it has a pricing table for running on more than one node.

Now another option is to go with Java's Executors, but if you foresee having at least some degree of complexity in your scheduling and some requirements changes, I'd suggest going with something more reliable and flexible.

Spring scheduling can be pretty powerful, and does the job on number of cases, but again, if you plan on moving to DB job controlling, multiple nodes or need to fine tune your jobs execution, Quartz does have many feature to support it.

Here's a page from Quartz documentation depicting it's latest features.

I've added a base code that can be used to create a job out of the box, having just some boilerplate code for Spring 4 and Quartz to kickstart me faster should I ever need to use it again.

The most important part is contained in the Gist below and configures the three beans that represent the Job, the Trigger for it's schedule and the Scheduler itself. See the Quartz documentation for further details. This link contains all the code for it (using sbt as build tool): https://github.com/eduardohl/quartz-boiler. Code has been documented, so do a clean up if you plan on using it.