Recommended way to implement a Quartz job that holds state - java

I need to implement a Quartz job that behaves differently depending on how many times it has been run.
What would you say is the best (or at least a good) way to do that ?
Keeping a counter as state doesn't seem to work since it looks like Quartz recreates it's jobs every time.
Thanks.

This is what the Quartz PersistJobDataAfterExecution annotation allows you to easily implement without using any extra framework / logic.
From PersistJobDataAfterExecution (Quartz 2.2.0) javadoc:
An annotation that marks a Job class as one that makes updates to its
JobDataMap during execution, and wishes the scheduler to re-store the
JobDataMap when execution completes.
So when your job starts you simply read your job execution counter from the JobDataMap that is passed to the job's execute method. If the counter is not present in the JobDataMap, you initialize it with 0. At the end of your job execution you increment the counter in the JobDataMap. This updated counter value will then be available during the next job execution.

Related

Quartz scheduler - synchronizing jobs

I use Quartz scheduler for executing 10 jobs. All of these jobs have their own trigger. So they are executed asynchronously.
However now I need 2 of these jobs to be executed in more specific way. Lets say that Job1 is executed every even minute and Job2 every odd minute. Now I want Job2 to wait for Job1 to be finished.
Example: Job1 starts to execute at 10:02. At 10:03 Job2's trigger is fired. But before Job2 starts to execute, it will look at Job1 if it has finished.
I found annotation #DisallowConcurrentExecution for job class that implements Job interface. I thought that this will do the thing, but then I read that it will only disallow concurrent execution of jobs with the same JobKey(name,group). But I cant have the same JobKey for my jobs. So this annnotation is good for just one job I guess.
Do you have some idea how I can solve my issue? Many thanks.
Check the details of existing running job with this call and take appropriate action..
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
Refer this Jobs status
You can define a static variable to mark Job1 finished or not. When you create Job2, in your code, you can check the static variable before execute.

quartz if method takes longer then repeat interval start when finish

I have a job that runs every 2 minutes:
org.quartz.CronScheduleBuilder.cronSchedule("0 0/2 * * * ?").withMisfireHandlingInstructionDoNothing()
Currently, if the job takes more than 2 minutes, Quartz waits another 2 minutes to run it again.
How do I start it right away if it took more than the scheduled interval?
I do not want Quartz to create another job and run both concurrently, because in case the job always fails, I don't want to fill the job queue up, I want the job to run with at least a 2 minute interval.
Misfire instructions tell Quartz what to do when a job runs late.
If a job didn't fire on time because the scheduler was down, or because the previous run took longer than expected, or any other cause, that's a misfire. And you can use misfire instructions like withMisfireHandlingInstructionDoNothing() to tell Quartz what to do.
In this case, you're telling Quartz: "If this job takes longer than expected, that is my problem, not yours. Don't fire up another instance concurrently, don't wait for it to finish. Ignore it. Do nothing".
If you want to change this, you can use a different misfire instruction, like withMisfireHandlingInstructionFireAndProceed(), which will instruct Quartz to fire a misfired job as soon as the previous one finishes.
You can look up available misfire instructions for each type of schedule in the API Javadoc.

Task scheduling with Quartz

I am using Quartz for scheduling parallel tasks, How can I get job running time in Quartz?
JobExecutionContext expose a some useful methods:
getJobRunTime: returns the time only after the job has actually completed
(you may want to use a JobListener to call it when job finished the
execution).
getFireTime: get the actual time the job started, so you can the current Date to calculate the elapsed time (you can call this method even inside the Job itself).
Note: To know "how long it WILL takes to run one job" you have to implement on your own doing some simple math to get the % of completion. Quartz itself doesn't have such a feature.

when a quartz job fires, is it a new job class instance?

I am very new to Quartz and I have some doubts about the jobs lifecycle.
Let's suppose I have a single job configured to do some stuff.
The job fires and ends its work. When it fires again is it the same instance (maybe set to sleep and awaken by the scheduler) or is it a new job instance (once the job ends it is killed and when the trigger condition is met again a new job instance is created)?
I ask such question because when I debug my application (spring 3 mvc with quartz support) I see new instances of the job and new threads with SimpleThreadPool$WorkerThreadRun() opened for every time the job is fired so that the SimpleThreadPool$WorkerThreadRun() threads are piled up and never terminated.
I just want to know if this behaviour is allright or I'm bound to fill the memory ;-)
Can anyone give me some explanation? Thanks in advance.
Quartz creates new instance of your job class every time it wants to trigger that job. Suppose you have hundreds of thousands of jobs scheduled to trigger very infrequently - it would be a waste of memory to keep all those jobs in memory.
However if you are using Spring support for Quartz, especially the MethodInvokingJobDetailFactoryBean, Spring will handle the lifecycle of your job (it basically calls designated method of one of your beans). But seems not to be the case in your application.
Of course after the job is done and no other references are pointing to it (which is the normal case) garbage collector will eventually release the memory occupied by the job).
Finally about threads - Quartz creates a fixed pool of worker threads (see org.quartz.threadPool.threadCount configuration option). Every time you run a job Quartz may decide to use a different thread - but it won't create new thread per every trigger.
I will write about version 2.1.5 (latest version), but it could also be true for other versions.
Job-instance created by some instance of "JobFactory" with "newJob"-function (SimpleJobFactory, for example). Call to "newJob" executed in "initialize"-method of JobRunShell-class. JobRunShell-object held in local variable of "QuartzSchedulerThread.run" and not stored in any other list or field.
So, new Job-instance created for every trigger time and after execution it will be cleaned up normally by garbage collector.

Ensure that Spring Quartz job execution doesn't overlap

I have a Java program that executes from Spring Qquartz every 20 seconds. Sometimes it takes just few seconds to execute, but as data gets bigger I'm sure it run for 20 seconds or more.
How can I prevent Quartz from firing/triggering the job while one instance is still being executed? Firing 2 jobs performing same operations on a database would not be so good. Is there a way I can do some kind of synchronization?
Quartz 1
If you change your class to implement StatefulJob instead of Job, Quartz will take care of this for you. From the StatefulJob javadoc:
stateful jobs are not allowed to
execute concurrently, which means new
triggers that occur before the
completion of the execute(xx) method
will be delayed.
StatefulJob extends Job and does not add any new methods, so all you need to do to get the behaviour you want is change this:
public class YourJob implements org.quartz.Job {
void execute(JobExecutionContext context) {/*implementation omitted*/}
}
To this:
public class YourJob implements org.quartz.StatefulJob {
void execute(JobExecutionContext context) {/*implementation omitted*/}
}
Quartz 2
In version 2.0 of Quartz, StatefulJob is deprecated. It is now recommended to use annotations instead, e.g.
#DisallowConcurrentExecution
public class YourJob implements org.quartz.Job {
void execute(JobExecutionContext context) {/*implementation omitted*/}
}
If all you need to do is fire every 20 seconds, Quartz is serious overkill. The java.util.concurrent.ScheduledExecutorService should be perfectly sufficient for that job.
The ScheduledExecutorService also provides two semantics for scheduling. "fixed rate" will attempt to run your job every 20 seconds regardless of overlap, whereas "fixed delay" will attempt to leave 20 seconds between the end of the first job and the start of the next. If you want to avoid overlap, then fixed-delay is safest.
Just in case anyone references this question, StatefulJob has been deprecated. They now suggest you use annotations instead...
#PersistJobDataAfterExecution
#DisallowConcurrentExecution
public class TestJob implements Job {
This will explain what those annotations mean...
The annotations cause behavior just as
their names describe - multiple
instances of the job will not be
allowed to run concurrently (consider
a case where a job has code in its
execute() method that takes 34 seconds
to run, but it is scheduled with a
trigger that repeats every 30
seconds), and will have its JobDataMap
contents re-persisted in the
scheduler's JobStore after each
execution. For the purposes of this
example, only
#PersistJobDataAfterExecution
annotation is truly relevant, but it's
always wise to use the
#DisallowConcurrentExecution
annotation with it, to prevent
race-conditions on saved data.
if you use spring quartz, i think you have to configure like this
<bean id="batchConsumerJob"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myScheduler" />
<property name="targetMethod" value="execute" />
<property name="concurrent" value="false" />
</bean>
I'm not sure you want synchronisation, since the second task will block until the first finishes, and you'll end up with a backlog. You could put the jobs in a queue, but from your description it sounds like the queue may grow indefinitely.
I would investigate ReadWriteLocks, and let your task set a lock whilst it is running. Future tasks can inspect this lock, and exit immediately if an old task is still running. I've found from experience that that's the most reliable way to approach this.
Perhaps generate a warning as well so you know you're encountering problems and increase the time interval accordingly ?
put them in a queue
Even if the time exceeds 20 second current job should be finished & then the next should be fetched from the queue.
Or you can also increase time to some reasonable amount.
You can use a semaphore. When the semaphore is taken, abandon the 2nd job and wait until the next fire time.

Categories