Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quartz jobs - disallow concurrent execution group-wide?

using Quartz, I'd like few jobs (say about 10) to execute as a chain - i.e. NOT concurrently. They should be executed after an "accounting day change" event occur but since they all access the same DB, I dont want them to start all together. I want them to be executed sequentially instead (order doesnt matter).

I have an idea to put them into a group - say "account_day_change_jobs" and configure Quartz somehow to do the rest for me :-) Means - run sequentially all jobs from the group. I tried the API doc (both 1.8 and 2.1), tried google but didnt find anything.

Is it possible? Is it even reasonable? Other ideas how to achieve the behavior I want?

Thanks very much for any ideas :-) Hans

like image 898
user1756581 Avatar asked Oct 27 '25 05:10

user1756581


1 Answers

The Trigger Listener class below should re-schedule any jobs that attempt to execute while another job that the listener has been configured for is running. Ive only lightly tested it but for simple cases it should be suitable.

public class SequentialTriggerListener extends TriggerListenerSupport {

private JobKey activeJob;
private Scheduler activeScheduler;
private Queue<JobDetail> queuedJobs = new ConcurrentLinkedQueue<JobDetail>();

public String getName() {
    return "SequentialTriggerListener";
}

public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
    synchronized (this) {
        if (activeJob != null) {
            getLog().debug("Queueing Sequential Job - " + context.getJobDetail().getKey().getName());
            JobDetail jd = context.getJobDetail();
            activeScheduler = context.getScheduler();
            jd = JobBuilder.newJob().usingJobData(jd.getJobDataMap()).withIdentity(getName() + ":" + jd.getKey().getName(), jd.getKey().getGroup())
                    .ofType(jd.getJobClass()).build();
            queuedJobs.add(jd);
            return true;
        } else {
            activeJob = trigger.getJobKey();
            getLog().debug("Executing Job - " + activeJob.getName());
            return false;
        }
    }
}

public void triggerMisfired(Trigger trigger) {
    triggerFinalized(trigger);
}

public void triggerComplete(Trigger trigger, JobExecutionContext context, CompletedExecutionInstruction triggerInstructionCode) {
    triggerFinalized(trigger);
}

protected void triggerFinalized(Trigger trigger) {
    synchronized (this) {
        try {
            if (trigger.getJobKey().equals(activeJob)) {
                getLog().debug("Finalized Sequential Job - " + activeJob.getName());
                activeJob = null;
                JobDetail jd = queuedJobs.poll();
                if (jd != null) {
                    getLog().debug("Triggering Sequential Job - " + jd.getKey().getName());
                    activeScheduler.scheduleJob(jd,TriggerBuilder.newTrigger().forJob(jd).withIdentity("trigger:" + jd.getKey().getName(), jd.getKey().getGroup())
                            .startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withRepeatCount(0).withIntervalInMilliseconds(1)).build());
                }
            } else {
                // this should not occur as the trigger finalizing should be the one we are tracking.
                getLog().warn("Sequential Trigger Listener execution order failer");
            }
        } catch (SchedulerException ex) {
            getLog().warn("Sequential Trigger Listener failure", ex);
        }
    }

}

}

like image 51
Marius Gleeson Avatar answered Oct 30 '25 13:10

Marius Gleeson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!