I want to get the delay between the time a job was supposed to execute and the time it actually executed for the most recent execution. For example, if a job was supposed to fire at 8pm and it actually fired at 8.10pm, the result should be 10 minutes.
I know that I can use Trigger.getPreviousFireTime() to get the last time it actually executed, but I can't see any way to get the corresponding scheduled time (e.g. 8pm for the example above), is this possible?
Inside your job use the following code:
#Override
public void execute(final JobExecutionContext context) {
long diffInMillis =
new Date().getTime() - context.getScheduledFireTime().getTime();
//...
}
As you probably guessed context.getScheduledFireTime() is the time when job was suppose to run (ideally the difference should be close to 0).
Note that if your job is late more than 10 minutes (configurable) it might not fire at all - it depends on your misfire instruction set up.
Related
I had one quartz job doing some stuff and taking lot of time for one particular case and others are very quick. So I don't want to stop my job waiting when one slow case is running for very long time and other things are complete. This job runs and checks doStuff flag. when doStuff==1 run do things and make value to 0. So that when next time job is triggered it should not run already done stuff.
So to solve above problem I created 2 jobs. A- quick performing job, B-slow moving job.
I have 2 quartz jobs A & B running concurrently and using one flag to decide whether to run job & do stuff or to run and exit without doing any stuff.
I have a flag doStuff and it has initial value as 0 . when it's value is 1 then both job should start doing stuff and when they finish they should update value back to 0. When value is 0 and job started then this job won't do it'a stuff.
The work both job A & B doing is exactly same but different parameters.
Ideally both job should run when flag is 1 and do stuff and update value to 0.
But when first job runs and completes before starting second job, it is updating value to 0 and when second runs it reads value 0 and won't do any stuff.
The doStuff flag is DB column. I can add one more column for job B, but that's not a good design as we may get requirement of job C, job D and I can't add column for each requirement.
Is there any better way to handle this problem?
Note: I am new to Quartz framework.
Tried using new column for flag but not a good design. Tried locking but that also won't solve problem .
Below is how execute method of InterruptableJob looks like
public void execute(JobExecutionContext jobContext) throws JobExecutionException {
JobDataMap jobDataMap = jobContext.getMergedJobDataMap();
final long customerId = jobDataMap.getLong(CUSTOMER_ID_KEY);
List < QAgentAssetSourceInfo > customerAgents = getValuesBasedOnDoStuff();
// below code is in Runnable run method and will be started in new thread
{
failedAgents.putAll(agentMgmtHelper.get().doStuff(customerAgents, customer.getId(), null, batchSize));
// we are done with stuff now make value to 0
unsetDoStuff();
});
}
I'm using spring-boot #Scheduled annotation with fixedDelay in milliseconds as documented in javadoc:
Execute the annotated method with a fixed period in milliseconds between the end of the last invocation and the start of the next.
Code:
#Scheduled(fixedDelay=1000)
public void task() {
LOG.info("START: " + System.currentTimeInMillis());
....do some work here...
LOG.info("END: " + System.currentTimeInMillis());
}
And sometimes I get such output that time between previous task end and next task starts is less than 1000ms for about 2-30 milliseconds.
Is it normal due to some granularity or why is it happening? Is there any guaranties about this delta value?
There are different ways in which you can use #Scheduled annotation.
According to the documentation:
The fixedRate invokes the method every t ms but the time delay is measured from the start of the invocation. If t ms are passed and the method is still in execution then the next invocation will wait for it to finish and will invoke right after the first one. Try putting Thread.sleep(3000) in your method. I think that your method is taking about 950ms to complete.
If you want to wait after finishing the execution you can use fixedDelay.
Obviously it cannot be guaranteed since you're most likely not on a real time system. Depending on what the CPU(s) do at the moment it can vary like that. It's quite hard to do something like that actually on most PC's due to the OS scheduling calls and so on (unless you have direct access to the CPU/GPU but even then)
How #Scheduled(fixedDelay=1000) works is, it will run this void method every 1000 ms(If this task finish execution < 1000 ms or this will run asynchronously). If > 1000ms it the execution task will get into a task queue in the Executor service used. There is no connection with the end of task and the start of next task but a connection with the start of a task and start of a next task.
I want a mechanism that will start a java program ( quite a big one ) depending on 2 conditions:
N new inserts in a MySQL table
Every 5 minutes interval.
I know that I can do this through crontab or using Timer or using Stored Procedure etc.
My plan is to write a Java class ( I am most familiar with ), Listener having two threads in parallel - Database Listener and Time listener threads each of them monitoring one of these conditions. If one says, yes, the parent class will start a new thread to run the Program.
I feel that it will be a heavy weight program. Is there some other option that I am overlooking at?
Write a single job. Have it execute regularly.
Effectively, you'll be doing some something of the nature of:
SELECT count(*) FROM table WHERE new = 1;
(or whatever)
Run that every second, 5 seconds, 10 seconds, whatever seems reasonable based on your activity.
When count == N, run your process. When "time since last run" == 5 minutes, run your process.
The process is the same, you just check it more often with the two criteria.
This offers an advantage that you won't get rogue race condition where the job fires TWICE (because Job A found the insert count that just-so-happens to have been 5 minutes from when the last job ran). Rare, yes, but race conditions always seem to actively seek "rare" events that "never happen".
As for scheduling, a crontab is easy because you don't have to maintain your process, keep it alive, daemonize, etc. etc.
If you're already running in a long running container (app server, tomcat, etc.) then that problem is already solved and you can just leverage that.
Downside of cron is it's granularity, it only runs at most every minute. If that too long, it won't work for you. But if it's ok, then there's real value in having a simple process that just lights up, does it's check, and quits. Of course, it will have to persist it's state somehow (it could look in a job log to see when the last job ran, for example).
Within java, there are lots of options: raw threads, sleeping, Timers, ScheduledExecutorService, something like Quartz, EJB Timer beans (if you're running a Java EE container).
But, I'm a KISS fan. If a cron job can do it, let it, and do it once.
It is actually not that big using a ScheduledExecutorService:
private static final Runnable PROGRAM_RUNNABLE = new Runnable() {
#Override
public void run() {
// run the program
}
}
private ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);
public static void main(String[] args) {
// database based
ses.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
boolean inserted = checkDatabase(); // check the insert in the db
if(inserted) {
PROGRAM_RUNNABLE.run();
}
}
}, 0, 1, TimeUnit.MINUTES);
// time based
ses.scheduleAtFixedRate(PROGRAM_RUNNABLE, 5, 5, TimeUnit.MINUTES);
}
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.
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