I am using quart library for scheduling in java. I have written a trigger like this
trigger = newTrigger().withIdentity("myTrigger", "myGroup").startNow() .withSchedule(cronSchedule(croneExpression).withMisfireHandlingInstructionFireAndProceed()) .forJob("myJob","myGroup") .build();
Now when i set the scheduler with cronexpression which is dynamically generated scheduler runs properly. But when server is shutdown during the period in which scheduler is set to fire , the values in quartz_trigger i.e. the next_fire_time in table is changed after the execution time of the job.Because of this the misfire of the scheduler do not work.So my purpose is not solved.So what can be the problem? Is any property in the quartz.properties to be set. I am not using job.xml(jobInitializer) to set the scheduler.
the values in quartz_trigger i.e. the next_fire_time in table is changed after the execution >time of the job
Yes, this is quartz actually does in case of misfires.
As per the misfire instruction provided while creating a trigger, quartz calculates how many times the misfired execution has to be executed.
As per your code , you have set the misfire instruction as "fireAndProceed" , So Quartz just executes the very first misfired execution ( and neglect all the subsequent remaining misfires). Ex: If you set the trigger to fire between 2Pm to 4pm with interval of 30 min and if scheduler was down during 2:29pm to 3.29pm, then only one trigger execution of time 2.30pm
will be executed ( and executions of 3.pm will be neglected).
Hope this answers your question. :-)
Related
I am creating a JobDetail as below,
JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity(queryId).usingJobData("ExecutionDelay",1).build();
I want it to first run after 1 hour.
The Trigger for the same is as below,
Trigger trigger = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInHours(1)).build();
But, when I am creating more than 1 Thread of the above code in a class, the Job gets triggered immediately for some of the Jobs.
Not sure what is wrong. Can some one help.
It is most likely because you do not set the start time when you create your trigger. If you do not set the start time explicitely, then the current time (new Date()) is assumed and then depending on the your trigger's misfire instruction (default is SMART_POLICY) and timing, the job may be fired immediately.
To solve the problem, you will need to set the trigger's start time to "new Date() + 1 hour".
I am using Quartz's JDBCJobStore. I added job details, trigger information into tables using CronScheduleBuilder.cronSchedule(). if any scheduled job fails, I need it to be retried given a number of retries and retry interval. So, how can I add those parameters into table for a job?
As far as I am aware , Quartz has no way of doing this. You will have to manage it yourselves.
if any job scheduler fails
I presume that above line is pointing to failure of any scheduled job.
As soon as, the trigger fires the associated job starts running. So, there are 2 possibilities of failure here.
Scheduler is made hard shutdown when the job is being executed.
Quartz can handle this at its best. We have request-recovery attribute set for every job.
IF set to true, we are telling quartz that, "Recover/rerun this job at scheduler next startup if scheduler is hard shutdown during its execution". More information on this attribute here.
The job has thrown an exception during its execution.
This might means in our business logic that it has failed.( Note : Quartz don't assume this job as failed. You will have to decide this in your lifecycle of job that it has failed because of this exception.)
You can handle this by including all the code in job's exeucute() method in a try/catch block.
If any critical exception occured, inside catch block we will handle it in a way that we want to re-schedule the job again( i.e. making the job to retry again ).
So, For this you can always create a new jobdetail and trigger ( by using some of the parameters in jobExecutionContext of failed job) to recreate/reschedule the job again .
I am using quartz scheduler for scheduling a particular job. I am using both trigger types simple and cron. I have set the interval time as 4 minutes for testing purpose.
If the first run takes 2 minutes to execute then second run starts after 2 minutes the first run finishes. This should not happen. In this case interval time gets reduced to 2 minutes. This should not happen. The second job should start 4 minutes after the first job finishes. Is there any way to do this.
You should schedule the job once with 4 minutes delay, after job completes (use job listener to catch the moment), reschedule it again at the same 4 minutes interval.
Also, if it is not necessary to use the quartz, it could be enough to use java.util.concurrent.ScheduledExecutorService.
I have an application using the Quartz Scheduler to schedule jobs. The application is currently running Quartz version 1.6.2. My JobStore is org.quartz.impl.jdbcjobstore.JobStoreTX with an Oracle database backing it. Clustering is turned on, but there's only one scheduler using the database. My Quartz threadPool is configured as follows:
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 5
My jobs are long running, so it's fairly common to have 5 jobs running (the maximum allowed by my thead pool) when triggers fire new jobs. The newly triggered jobs misfire and I see log messages like the following:
2011-05-20 04:09:30,097 INFO [QuartzScheduler_scheduler-servername-111305822374881_MisfireHandler] o.q.p.h.LoggingTriggerHistoryPlugin - Trigger DEFAULT.JobName1 misfired job DEFAULT.DEFAULT at: 04:09:30 05/20/2011. Should have fired at: 04:08:29 05/20/2011
2011-05-20 04:09:30,120 INFO [QuartzScheduler_scheduler-servername-111305822374881_MisfireHandler] o.q.p.h.LoggingTriggerHistoryPlugin - Trigger DEFAULT.JobName1 misfired job DEFAULT.DEFAULT at: 04:09:30 05/20/2011. Should have fired at: 04:09:30 05/20/2011
2011-05-20 04:09:30,125 INFO [QuartzScheduler_scheduler-servername-111305822374881_MisfireHandler] o.q.p.h.LoggingTriggerHistoryPlugin - Trigger DEFAULT.JobName2 misfired job DEFAULT.DEFAULT at: 04:09:30 05/20/2011. Should have fired at: 04:08:30 05/20/2011
2011-05-20 04:09:30,138 INFO [QuartzScheduler_scheduler-servername-111305822374881_MisfireHandler] o.q.p.h.LoggingTriggerHistoryPlugin - Trigger DEFAULT.JobName2 misfired job DEFAULT.DEFAULT at: 04:09:30 05/20/2011. Should have fired at: 04:09:30 05/20/2011
2011-05-20 04:11:29,998 INFO [QuartzScheduler_scheduler-servername-111305822376676_MisfireHandler] o.q.impl.jdbcjobstore.JobStoreTX - Handling 2 trigger(s) that missed their scheduled fire-time.
Once a running job finishes, one of the misfired jobs will get picked up and run normally. However, Quartz seems to pick up a misfired job randomly, with no regard to the order the jobs had been originally scheduled to execute. Ideally, I'd like them to be picked up in the order they were supposed to have run, based on their original fire times.
Is it possible to make my waiting (misfired) jobs get fired in the order they were triggered once space in the Quartz ThreadPool becomes available?
When quartz handles a trigger that has missed it's fire time it will update the nextFireTime of the trigger. By default a trigger will be considered missed if it's nextFireTime is over 60 seconds in the past. Missed triggers should still be selected based on nextFireTime and priority order but I'm guessing it seems random because some triggers have been updated and others haven't.
I would suggest increasing the org.quartz.jobStore.misfireThreshold property. See http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigRAMJobStore.html (although the property is identical for all JobStores). This should make it less likely for your triggers to be re-scheduled.
I sounds like you are running into a misfiring scenario (a scenario where there are more jobs ready to be executing than there are worker threads). Set the misfire instruction and/or priority property on the triggers to change how each behaves after it has past its fire time.
Also, you could consider increasing the misfire threshold, which would change the amount of time that a trigger can be "late" waiting for a thread to execute on before it is considered misfire (and has its misfire instruction applied to it).
Is it possible to make my waiting (misfired) jobs get fired in the order they were triggered once space in the Quartz ThreadPool becomes available?
The "do nothing" instructions will leave the fire times as-is.
Looking at the quartz thread pool , it uses a wait()/notify() loop, which is not fair, and will randomly select a new thread when multiple threads are waiting.
You could use your own instance of ThreadPool which is fair. Copy the code from SimpleThreadPool, but replace the locking around nextRunnableLock with a java.util.ReentrantLock, passing true to the fair constructor. In your modified SimpleThreadPool, use ReentrantLock.lock()/unlock() instead of synchronized, and use ReentrantLock.newCondition().signal()/await() instead of wait/notify, and it might solve your problem.
In case of a CronTrigger, the method updateAfterMisfire() may re-schedule the task at new Date() case MISFIRE_INSTRUCTION_FIRE_ONCE_NOW policy.
If several task are misfired, several of them may be rescheduled at the same time (same millisecond), because computer runs fast.
As a consequence, and if no priority defined, the scheduler will pick-up the first next task, all with same NextFireTime, according to key or full name.
updateAfterMisfire() method should have re-schedule the task to a unique date using a Thread.sleep(25), as an example.
For my application I create jobs and schedule them with CronTriggers. Each job has only one trigger and both the job name and the trigger names are the same. No jobs share a trigger.
Now when i create a cron trigger like this "0/1 * * * * ?" which instructs the job to execute every second, it works just fine.
The problem rises when I first pause the job by calling:
scheduler.pauseJob(jobName, jobGroup);
and then resuming the job after let's say 50 seconds with:
scheduler.resumeJob(jobName, jobGroup);
What I see is that for these 50 seconds the job did not execute as requested. But the moment I resume the job I see 50 executions of the job at the same time!!!
I thought that this was due to the default setting for the misfire instruction but even after setting the trigger's misfire instruction upon creation to this:
trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
The same thing happens. Can anyone suggest a way to fix this?
The CronTrigger works by remembering the nextFireTime. After creating the trigger the nextFireTime is initialized. Every time the job is triggered nextFireTime is updated. Since the job is not triggered when paused nextFireTime remains "old". So after you resume the job the trigger will return every old trigger time.
The problem is, the trigger doesn't know it is being paused. To overcome this there is this misfire handling. After resuming the jobs the trigger's updateAfterMisfire() method will be invoked which corrects the nextFireTime. But not if the difference between nextFireTime and now is smaller than the misfireThreshold. Then the method is never called. This threshold's default value is 60,000. Thus if your pause period would be longer than 60s everything would be fine.
Since you have problems I assume it is not. ;)
To workaround this you can modify the threshold or use a simple wrapper around CronTrigger:
public class PauseAwareCronTrigger extends CronTrigger {
// constructors you need go here
#Override
public Date getNextFireTime() {
Date nextFireTime = super.getNextFireTime();
if (nextFireTime.getTime() < System.currentTimeMillis()) {
// next fire time after now
nextFireTime = super.getFireTimeAfter(null);
super.setNextFireTime(nextFireTime);
}
return nextFireTime;
}
}
If you pause the job, the trigger will continue to fire, but the executions will queue up until the job is resumed. This isn't a misfiring trigger, so that setting will have no effect.
What you want to do, I think, is programmatically disable or remove the cron trigger, rather than pausing the job. When you want to resume, then re-add the trigger.
Since 1.6.5 at least (the earliest version of quartz at my fingertips), the scheduler has a pauseTrigger method that takes the name/group as parameters. This means you don't have to have a sub-class of every trigger type you use, nor do you have to do funky deletion/insertion tricks.
Both of these are important to me because 1) our database has a strict no-deletes policy and 2) the custom datastore I use doesn't support trigger sub-classes.
you can add these code in org.quartz.impl.jdbcjobstore.JobStoreSupport#resumeTrigger(Connection conn, TriggerKey key)
OperableTrigger trigger = getDelegate().selectTrigger(conn, key);
if (trigger.getNextFireTime().getTime() < System.currentTimeMillis()) {
trigger.setNextFireTime(trigger.getFireTimeAfter(null));
}
JobDetail job = retrieveJob(conn, status.getJobKey());
storeTrigger(conn, trigger, job, true, status.getStatus(), false, false);
Using these code, when the paused job be resumed it will not be fired at once.On the other hand, it will be fired at next fire time which is calculated by resumed time