Using #DisallowConcurrentExecution in Quartz scheduler - java

I am sorry if this question is too naive,
I am expecting the jobs to be scheduled so that it executes one by one, and not parallely.It is executed only once.
From docs, #DisallowConcurrentExecution is
An annotation that marks a {#link Job} class as one that must not have multiple instances executed concurrently (where instance is based-upon a {#link JobDetail} definition - or in other words based upon a {#link JobKey}).
But when I schedule a job with same JobKey, I am getting
Failed to schedule a job org.quartz.ObjectAlreadyExistsException
If I generate a different JobKey, it is not heeding to #DisallowConcurrentExecution and the job is getting executed in parallel(as mentioned in docs).
Please suggest how can I achieve this, any pointers would really help!
PS: I do not know the jobs that would be scheduled. So, I need some method to dynamically link up the jobs,if the job is already running.

Same JobKey = same job.
Different JobKey = different job.
Quartz won't let you use the same JobKey more than once because that'd be two jobs with the same key. Like having two users with the same ID.
What you need to do is schedule different JobTriggers for the same JobKey.
#DisallowConcurrentExecution avoids overlapping executions of the same job. If you use a different JobKey, it's not the same job anymore, so the annotation doesn't have any effect. But for a given JobKey with several JobTriggers, #DisallowConcurrentExecution will keep the triggers from launching a new execution of the job, if the previous one hasn't finished yet.
I suggest having a look at Quartz's documentation to get a deeper understanding of the above concepts.

Related

Re-scheduling a task that executes once using Spring Trigger

I have a requirement where I need to schedule a task (from UI) that will execute only once. After completion, I should be able to re-schedule (from UI) the same task again.
I know #Schedule won't work here as I need to execute only once. So after further searching I am able to schedule the task to execute only once at specific time using TaskScheduler with Runnable and Date and also along with #Async. However I am unable to make it reschedule.
Looks like using quartz might be possible, but I haven't gone through it yet.
Is it possible to implement my requirement with Spring Trigger. I can see only two implementation of trigger interface CronTrigger and PeriodicTrigger.
Please suggest any possible approaches.
Including initial piece of code would be helpful.
The easiest way I see would be to create a regularly scheduled "trigger" method in a Spring bean that checks a certain condition and only executes the "real" action when the condition is met (e.g. the time you entered in the UI is in the past and the job has not started yet):
#Scheduled(fixedDelay = 5000)
public void trigger() {
if(condition){
//... do the action
}
}
This requires some persistence to store the "job metadata" like the execution date and the current state of the job, but that seems "lighter" than working with threads or including quartz just for this one use case.

How to save Quartz executed jobs?

One problem, after executed jobs, quartz delete jobs from database qrtz_triggers table, but in specific situation needed to repeat job which is failed.
Is any configuration options or way to store jobs to another table after execute???
Thanks
If you are using JDBCJobStore, your jobs are stored in a table like QRTZ_JOB_DETAILS, and your simple triggers are stored in QRTZ_SIMPLE_TRIGGERS, your cron trigers are stored in QRTZ_CRON_TRIGGERS, and all the triggers are stored in QRTZ_TRIGGERS.
If you expect your job is durable and remains when no triggers are associated to the job, you should call storeDurably(true) when building your JobDetail. For example:
JobDetail jobDetail = JobBuilder.newJob()
.ofType(DataMapJob.class)
.withIdentity("dataJob", "dataJobGroup")
.storeDurably(true)
.requestRecovery(true)
.build();
Hope it helps.
This is exactly what the durable flag is for. Durable jobs remain registered in Quartz even if there are no triggers associated with the job. On the other hand, non-durable jobs are automatically deleted by Quartz where there are no associated triggers (e.g. after all associated triggers fired and have been deleted by Quartz).
For details, you can refer to JobDetailImpl javadoc.

Is there a way to simulate a trigger misfire in Quartz? (Java)

I'm looking for a way to simulate or force a trigger misfire programatically. Here's the scenario:
I have a job set to trigger but the job requires some underlying resource that may be unavailable at times. If the resource is unavailable, I would like Quartz to re-fire the trigger later based on the misfire policy.
I've explored two options that are similar but not quite what I'm looking for:
Throwing a JobExecutionException with refireImmediately set to true:
Works, but doesn't delay execution based on misfire policy; this
would hammer the resource availability check.
Scheduling a second trigger at some fixed interval of time in the
future: Also works, but doesn't take into account misfire policy.
This means a job could wind up with a bunch of retries queued up
stemming from different failed runs.
Any ideas or anything I'm missing? Thanks!
If I got it right, you don't need to force or simulate a misfire because the resource availability is "something your Job can handle".
Misfires exists and are managed by Quartz for situations like server shutdown or other "unexpected problems" that prevent Job execution.
You have two options to follow to implement a simple fault-tolerance retry logic;
your Job can execute it's logic only when the underlying resource is available, so you can:
Wait for the resource to become availabile:
in this case your job waits and repeat the check for the resource availability, eventually after a short timeout, the job can give up and end.
Just do nothing if the resource is not available:
in this case the job ends without doing anything and the it will fire normally and retry according the Trigger definition.
In both cases, if the resource is avaliable, the Job can execute it's inner logic and use the underlying resource. (No misfires, because the Job was actually executed)
This can be done using a Trigger, setting the misfire policy you need in case the Job cannot be executed at all. See This great and detailed article on Quartz misfires.
In your situation, If you want to execute a job one time every day:
Define a Cron trigger that fires multiple times in a day in a given span of time, for exemple, every 15 minutes from 8:00 AM to 12:00 AM:
0 0/15 8-12 * * ?
Buld a Job that use one of the two approaches described before
The first time your Job inner logic executes (that is, the resource is available) your job will save a "job executed flag" with the day of execution somewhere on DB.
On the following trigger executions, the Job will check the flag and will not execute it's inner logic again.
Also, if your job will take long time to finish, you may want to prevent concurrent execution of the same job using the following annotation on the job implementation:
#DisableConcurrentExecution
See Quartz tutorials for more informations on job execution.

Stop single quartz scheduler

I have 5 different quartz schedulers which implement 5 different jobs. If I am stopping one scheduler, remaining schedulers are getting stopped. Why?
I'm pretty sure your actually creating references to the same Scheduler, you need to give each scheduler a different "SchedulerName". At the moment it looks like each time your creating a new scheduler its defaulting the SchedulerName.
The "job executor" is actually not the SchedulerFactoryBean. It is the Scheduler bean(to be precise calling its start method invokes the aggregated QuartzScheduler.start method which fires the Trigger-s), provided by the SchedulerFactoryBean. As a matter of fact this Scheduler is stored(and looked-up) under the schedulerName(which if not explicitly set has the same default value for every configured SchedulerFactoryBean) in the SchedulerRepository singleton(SchedulerRepository.getInstance()).
That's how unless you set a different schedulerName for your SchedulerFactoryBean-s, you will always get the same scheduler by each and every SchedulerFactoryBean-s
http://forum.springsource.org/showthread.php?40945-Multiple-Quartz-SchedulerFactoryBean-instances
I know this refers to Spring Beans but i still think the same applies here.

how many triggers can a single instance of SchedulerFactory have?

My application may fire around 1000's or more triggers everyday. Each of these is categorized into 4 categories:
morning(9am)
afternoon(1pm)
evening(6pm)
night(10pm)
And at each of these times, there will be 100's of trigger fired. Below is code
SchedulerFactory schdFact = new StdSchedulerFactory();
Scheduler schd;
for(ecah morningSchedulers){
// some logic for instantiating trigger
AbstractTrigger trigger = (AbstractTrigger) newTrigger().withSchedule(cronSchedule("0 0"+mAlert+"0,0,0 * * ?")).build();
trigger.setStartTime(strtDat);
trigger.setEndTime(endDat);
final JobDetail job = newJob(AlertJob.class).build();
schd.scheduleJob(job, trigger);
}
I have 2 questions here
Should I instantiate scheduler inside for loop or outside and schedule many triggers to the same scheduler. i.e. schd = schdFact.getScheduler(); where should I write this line?(inside or outside for loop)
I have to reschedule some of these triggers. i.e. stop on some condition and start again.
how many triggers can a single instance of SchedulerFactory have?
There is a similar question in the official FAQ:
How many jobs is Quartz capable of running?
This is a tough question to answer... the answer is basically "it depends". [...] So, the limiting factor of the number of Triggers and Jobs Quartz can "store" and monitor is really the amount of storage space available to the JobStore (either the amount of RAM or the amount of disk space).
Also remember about this:
[...] The actual number of jobs that can be running at any moment in time is limited by the size of the thread pool. If there are five threads in the pool, no more than five jobs can run at a time.
If you have thousands of triggers (you aren't confusing triggers and trigger executions?), consider JDBC storage. But if you have only few triggers but running several times a day, RAM store is enough.
Should I instantiate scheduler inside for loop or outside and schedule many triggers to the same scheduler
Definitely have only a single scheduler for the whole application. It is rare to have more than one scheduler in an application, see: Utilizing Multiple (Non-Clustered) Scheduler Instances.
Create the scheduler once and treat as a singleton.
I have to reschedule some of these triggers. i.e. stop on some condition and start again.
This is, again, explained in the documentation: Updating an existing Trigger. Basically you need to know the trigger key:
// retrieve the trigger
Trigger oldTrigger = sched.getTrigger(triggerKey("oldTrigger", "group1");
// obtain a builder that would produce the trigger
TriggerBuilder tb = oldTrigger.getTriggerBuilder();
// update the schedule associated with the builder, and build the new trigger
// (other builder methods could be called, to change the trigger in any desired way)
Trigger newTrigger = tb.withSchedule(simpleSchedule()
.withIntervalInSeconds(10)
.withRepeatCount(10)
.build();
sched.rescheduleJob(oldTrigger.getKey(), newTrigger);
BTW if just want to run a job at a given single hour, there is an easier API. Instead of:
newTrigger().
withSchedule(
cronSchedule("0 0"+mAlert+"0,0,0 * * ?")
).
build()
You can simply say:
newTrigger().
withSchedule(
dailyAtHourAndMinute(mAlert, 42)
).
build();
Have a look at Lesson 6: CronTrigger of the official tutorial.

Categories