Simple question, I think.
I have org.springframework.scheduling.quartz.CronTriggerBean triggering one job once a day. Because this method can last a long time (over 24 hours), will the next day at the same time a new job be executed if the last one is not ended yet?
If yes - is it possible to turn off executing new jobs until the last one is finished?
My method is trans-coding videos and some days there a lot of videos and could last long.
Make the Job stateful, So it will prevent the new instance before the previous instance of the job ended.
You 'mark' a Job as stateful by having it implement the StatefulJob interface.
You will get more about stateful job here
Related
I have a QUARTZ JOB which is starts every 10 minutes.
If a JOB doesn't finish in 10 minutes, in the next 10th minute another JOB will start.
What I want is: the next JOB (after every 10 minute) should start only, if the previous JOB has finished running. Is there any way to do it?
Quartz Documentation
#DisallowConcurrentExecution is an annotation that can be added to the
Job class that tells Quartz not to execute multiple instances of a
given job definition (that refers to the given job class)
concurrently. Notice the wording there, as it was chosen very
carefully. In the example from the previous section, if
"SalesReportJob" has this annotation, than only one instance of
"SalesReportForJoe" can execute at a given time, but it can execute
concurrently with an instance of "SalesReportForMike". The constraint
is based upon an instance definition (JobDetail), not on instances of
the job class. However, it was decided (during the design of Quartz)
to have the annotation carried on the class itself, because it does
often make a difference to how the class is coded.
If you dont want SalesReportForMike and SalesReportForJoe to run concurrently ,then you can set the scheduler's ThreadPool size to 1. So at any given time only one job will run.
Also take a look at StatefulJob
Take a look at the DisallowConcurrentExecution annotation which will prevent multiple instances of the same job to run at the same time.
I'm trying to set up Quartz for the first time, and forgive me if I am just not understanding something. I'm wondering what is the best way to accomplish the following:
How to set up a job that must run a daily email report, and also be able to recover from a missed trigger so that: 1) the job knows what day the trigger was SUPPOSED to fire on. and 2) if (god forbid) the server is down for 3 days, Quartz will recover by running three missed days consecutively, also informing the job of what day each job represents. (execution order is not really important as long as I know what day each represents)
Right now I am just doing:
Trigger trigger = newTrigger()
.withIdentity("dailyTrigger", "scheduledReportEmail")
.startNow()
.withSchedule(dailyAtHourAndMinute(0, 5) .withMisfireHandlingInstructionFireAndProceed())
.build();
This only seems to recover by running once, no matter how many days get missed. Is that correct?
One approach I thought about is basically setting up 31 daily triggers, for days 1-31. Clunky.. and what might happen in February for those extra days? Is this the best approach?
I've also got weekly and monthly triggers to deal with but I figure if we're down for three weeks then we have bigger things to worry about :)
thanks for any advice....
Your use case is pretty standard and supported by Quartz. You just need "ignore misfires" policy:
Trigger trigger = newTrigger()
.withIdentity("dailyTrigger", "scheduledReportEmail")
.withSchedule(dailyAtHourAndMinute(0, 5)
.withMisfireHandlingInstructionIgnoreMisfires())
.build();
This basically means: I don't care that the trigger(s) misfired, just run it as soon as possible (that is most likely at application startup).
To figure out when given trigger was suppose to run (what was the scheduled time as opposed to current time), run this in your job:
void execute(JobExecutionContext context) {
final Date scheduled = context.getScheduledFireTime()
//...
}
See also
difference between last actual and scheduled fire time
issue when using quartz withMisfireHandlingInstructionIgnoreMisfires
Quartz scheduler misfire instructions explained - my article describing various misfire instructions
Would you please explain to me the exact mean of the StatefulJob in quartz and it's difference with none StatefulJob?
StatefulJob interface, provides 2 things,
first: only one job will be run any time
second: in (SimpleTriggerBean) you will not worry about your job running duration. it means that the next run will be done after delay time after ending of previous one.
StatefulJob guarantees only one job will be running at one time. For example, if you schedule your job to run every 1 minute, but your job took 5 minutes to complete, then the job will not be run again until the previous job has completed.
This is useful to make sure there is only one job running at any given time.
The next job will be run on the next schedule, not immediately after the previous job completed.
jobDetail.getJobDataMap().put("type","FULL");
This line is will decide we are using statefull or non-statefull.
If we are passing the argument then it will be statefull.
With out statefull there is no way to pass the arguments in execute method
In state full while execution time if we modify any value then the execution job will be lost it wont re-triggered at simultaneous process time.
Only one job will execute at a time the second will be sleep until the first one is completed.
In multi scheduling process the second job argument will be share to first job at run time. this is one type of disadvantage in multi scheduling process.
I have started using quartz scheduler in my application.I want to know whether we can find the actual start time of a scheduler and the actual time at which the scheduler ends.
You can use a JobListener for that.
The method jobToBeExecuted runs before the job starts and jobWasExecuted after it ends.
EDIT:
To further expand on the issue:
You can use the JobDetail object to store data about the job (look at getJobDataMap).
jobToBeExecuted method is called automatically each time the job is about to execute and it accepts a JobExecutionContext which has a method getJobDetails (look at section 1)
Same goes for jobWasExecuted, only this one is called after the job finished.
Look here for further information.
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