views:

674

answers:

3

This should be really easy. I'm using Quartz running under Apache Tomcat 6.0.18, and I have a jobs.xml file which sets up my scheduled job that runs every minute.

What I would like to do, is if the job is still running when the next trigger time rolls around, I don't want to start a new job, so I can let the old instance complete.

Is there a way to specify this in jobs.xml (prevent concurrent instances)?

If not, is there a way I can share access to an in-memory singleton within my application's Job implementation (is this through the JobExecutionContext?) so I can handle the concurrency myself? (and detect if a previous instance is running)


update: After floundering around in the docs, here's a couple of approaches I am considering, but either don't know how to get them to work, or there are problems.

  1. Use StatefulJob. This prevents concurrent access... but I'm not sure what other side-effects would occur if I use it, also I want to avoid the following situation:

    Suppose trigger times would be every minute, i.e. trigger#0 = at time 0, trigger #1 = 60000msec, #2 = 120000, #3 = 180000, etc. and the trigger#0 at time 0 fires my job which takes 130000msec. With a plain Job, this would execute triggers #1 and #2 while job trigger #0 is still running. With a StatefulJob, this would execute triggers #1 and #2 in order, immediately after #0 finishes at 130000. I don't want that, I want #1 and #2 not to run and the next trigger that runs a job should take place at #3 (180000msec). So I still have to do something else with StatefulJob to get it to work the way I want, so I don't see much of an advantage to using it.

  2. Use a TriggerListener to return true from vetoJobExecution().

    Although implementing the interface seems straightforward, I have to figure out how to setup one instance of a TriggerListener declaratively. Can't find the docs for the xml file.

  3. Use a static shared thread-safe object (e.g. a semaphore or whatever) owned by my class that implements Job.

    I don't like the idea of using singletons via the static keyword under Tomcat/Quartz, not sure if there are side effects. Also I really don't want them to be true singletons, just something that is associated with a particular job definition.

  4. Implement my own Trigger which extends SimpleTrigger and contains shared state that could run its own TriggerListener.

    Again, I don't know how to setup the XML file to use this trigger rather than the standard <trigger><simple>...</simple></trigger>.

+1  A: 

I accomplished something similar making my job classes implement StatefulJob, which ensures that no other jobs starts before the current running job finishes.

Hope that helps ;)

PD: I implemented it using JBoss... but I don't think that makes any difference.

rlopez13
helps somewhat but not really, see my comment #1 above.
Jason S
+1  A: 

when your Quartz job wakes up you can do:

JobDetail existingJobDetail = sched.getJobDetail(jobName, jobGroup);
    if (existingJobDetail != null) {
        List<JobExecutionContext> currentlyExecutingJobs = (List<JobExecutionContext>) sched.getCurrentlyExecutingJobs();
        for (JobExecutionContext jec : currentlyExecutingJobs) {
            if(existingJobDetail.equals(jec.getJobDetail())) {
                //String message = jobName + " is already running.";
                //log.info(message);
                //throw new JobExecutionException(message,false);
            }
        }
        //sched.deleteJob(jobName, jobGroup); if you want to delete the scheduled but not-currently-running job
    }
jimi
Looks interesting... you need to check against the existing JobExecutionContext, otherwise you'll always get the exception.Also there's an exception thrown by sched.getCurrentlyExecutingJobs() that needs to be caught.
Jason S
A: 

Hello Jason,

could you set the job as a StatefulJob, and for each trigger you create set the MisfireInstruction for the job to not fire if it is missed? Not sure what type of job you are using but you'll have to do some research into the misfireInstructions that are available for your trigger type.

Thanks, D

DMan