pausing job execution based on total number of jobs executed - quartz - java

Is it possible to change the CronTrigger state to WAITING or to some other value which stops the job execution till next day? I can pause the trigger which will stop job execution but then I have to manual resume this trigger.
Actually, I have a CronTrigger which executes job every day between say 8:00 AM - 12:00 PM, right now it's working fine but now I would like to add an aditional check that before executing every job it will check the total number of jobs executed and pause the execution till next day if the total executed jobs limit is reached.

You'll want to create a custom TriggerListener, which keeps track of the count, can veto job execution, and reschedules jobs for the next day (e.g. updates the triggers' startTime to "00:00:00" of the next day while leaving the cron expression to the same).

Related

Java Run Method every 30th second of a minute

I have the following while loop:
while (keepRunning) {
if (!once) {
// Run a test method every 30th second
// Run the new calculations from the database
new CalculatorDriver().run();
// Wait in the while loop for 1 second before looping again
TimeUnit.SECONDS.sleep(1);
}
}
This while loop will loop every second through the code, but now I want to run a method called: getNewCalculations() every 30th second of a minute, so for example, the method needs to run at:
18:26:30
18:27:30
18:28:30
I already found a way to run a method every x seconds:
Timer timer = new Timer();
timer.schedule(new Task(), 60 * 1000);
But I also need to start it at a specific point. In C# someone tried this to run a script every 30th and every 0th second: https://stackoverflow.com/a/53846390/10673107.
I could just add an if where the second can't be equal to 0, but I was wondering if there was a better way to do this.
How can I run it only in the 30th second?
Set an initial delay by calculating the number of seconds to wait until the next 30th second is due to arrive. If the current moment is :10, wait 20 seconds. If the current moment is :56, wait 34 seconds.
The Duration class may help with that, along with ZonedDateTime class.
If you read the Javadoc for Timer/TimerTask you will learn those classes were supplanted years ago by the Executors framework that arrived in Java 5.
Use a ScheduledExecutorService to schedule a task to run after an initial delay specified by you. After the initial delay, specify a repeating period of one minute.
Your task will then be repeating on the 30th second mark of every minute. Know that this scheduling is approximate. The host OS, the JVM’s internal scheduler, and garbage-collection all impact when the task actually runs. So each run may vary.
Or, if you want to protect against any politician-imposed anomalies on your region’s time-keeping, schedule only a one-time scheduled task rather than repeating task. Pass to that task a reference to the ScheduledExecutorService object. The task can then schedule its own next run after running the initial-delay calculation again.
Be sure to eventually shutdown your executor service. Otherwise its backing pool of threads may continue to run indefinitely even after your app ends, like a zombie 🧟‍♂️.
Be aware that any exception or error bubbling up to the scheduled executor service will silently halt any further scheduling.
All of these topics have been addressed many times already on Stack Overflow. Search to learn more.

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.

How to set new job each time with different interval

I'm pretty new to Quartz and I've come a cross the following requirement:
I need to create a scheduler that schedules single job that each time it ends it rescheduled but with calculated interval time.
For example:
1. Start job that ends after 15minutes, then when finished reschedule it to end after 1Hour, when finished reschedule it to end after 45 minutes...and so on...
The point is that when job finishes I dynamically calculate the next interval and need to fire the event again.
How to accomplish that with Quartz?
Thanks.
Provided you can trigger it explicitly for the first time, something like
scheduler.addJob(jobDetail, true);
scheduler.triggerJob(jobName, groupName); //(1)
and code the job class such a way that after its main work is done, calculate the next trigger time and schedule it before job exits. Something like
scheduler.scheduleJob(jobDetail, trigger); //(2)
Note that the the job trigger in code snippet (1) removes the job after its done. That means you will have to schedule it, in (2), as if its a new job as far as scheduler is concerned.

Understanding the ScheduledThreadPoolExecutor

I know that I must use this instead of java.util.Timer because of various reasons. So, to study this I was looking at the docs and I have a few questions:
How does scheduleWithFixedDelay() work ? My understanding is this: It first executes a task after a given delay. Once the task is done, it waits for the specified time and then executes the task again.
What happens when I submit a task to scheduleAtFixedRate() that takes a lot more time to execute than the specified delay ? Like I want the task to execute every 5 seconds but it takes 10 seconds to complete. My understanding is that the task will be held in a queue and will be executed once a core thread is available
Here is my understanding of how scheduleWithFixedDelay() and scheduleAtFixedRate() differ: scheduleWithFixedDelay() waits for the task to finish executing, waits for the specified time and then fires the task again where as scheduleAtFixedRate will just keep firing the task without caring if it has completed or not. Correct?
Correct.
Not quite. If a fixed-rate task takes longer than its period, it will run again immediately upon completion, but the next run is not waiting for a thread. See below.
A fixed-rate task does care whether its previous run has completed, just like a fixed-delay task. Per the documentation, "If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute."
Think of it this way:
For a fixed-delay task, you specify a period which will be the exact amount of time between runs. The actual duration of the task has no effect on the delay.
For a fixed-rate task, you specify a period which will be the maximum amount of time between runs. If the actual duration of the task is longer than the period, the rate is reduced, and there is effectively no delay.

Quartz next fire time is still previous trigger time?

I am using Quartz with Spring to schedule jobs. I have a job which has been scheduled to run every hour. The problem is that when the scheduled job takes more than an hour then the job's "next fire time" remains the old time and is not fired (since the fire time is already past).
My question is how can we change "next fire time" if the job takes more time than the scheduled time?
Try using #DisallowConcurrentExecution annotation. With this, you can ensure only one instance of your job would execute at one point of time i.e. (only one instance of jobdetail).
Hence, if your job is taking more time than 1 hour then this annotation will stop the
other instances (i.e other instances will wait until the first running job finishes the execution).
I just guessed ... not sure whether it will work or not.

Categories