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
Related
In my Spring program, I have a Scheduled task.
#Scheduled(cron = "0 0 0 2 * *") // hardcoded schedule
public void executeBatchJob() {
batchJob.execute();
}
I have a specification change and now have to let the user freely configure the date and time of execution via an API.
One way I came up was to run a scheduled task every morning at 0:00 and check if the date is indeed the date of execution. If true, check the time of execution and schedule the batch job to run at that time of the day.
Is there a "Spring" way of achieving this?
Triggers can be used to configure the scheduled jobs.
From the docs
The basic idea of the Trigger is that execution times may be determined based on past execution outcomes or even arbitrary conditions.
Check out this answer for detailed explanation.
I am using the Quartz Scheduler (version 1.8.3 due to project constraints) and I as assigned the task of creating an "MS Outlook-like" scheduler for Jobs specific to my project. Everything seems fine to work fine but I have a really huge problem with CronTriggers (this problem also exists in version 2.1 of Quartz):
I am using CronTriggers for recurrence patterns of DAILY, WEEKLY and MONTHLY. In addition to the recurrence pattern, I also provide an option for 'No. of occurrences'. This has become the bane of my life! CronTrigger does not provide an option for 'repeatCount' like SimpleTriggers do (bug: https://jira.terracotta.org/jira/browse/QTZ-242?page=com.atlassian.jira.plugin.system.issuetabpanels%3Achangehistory-tabpanel). Apparently this may be fixed in version 2.2 but I cannot wait that long nor do I believe my problem is unique!
A few options that I deemed worthy of investigation:
Calculate the 'EndTime' for the CronTrigger but using my own logic - this fails to cover all possible cases and is only approximate at best even for simple cases.
Use a TriggerListener or JobListener to keep track of no. of iterations of the job since I just need the job to stop after 'N' iterations and I have a 1:1 mapping from Job instance to Trigger. This does not seem very feasible and/or efficient by any stretch of the imagination.
Could any of you who have used CronTriggers with the option of 'No. of occurrences' please give some insights on how to solve this conundrum?
It seems that Quartz have implemented something that can help: TriggerUtils.computeEndTimeToAllowParticularNumberOfFirings.
I haven't tested it yet, but this is the code I have wrote for now:
CronTrigger trigger = newTrigger()
.withSchedule(cronSchedule(cronExpression))
.build();
Date endDate = TriggerUtils.computeEndTimeToAllowParticularNumberOfFirings((OperableTrigger) trigger,
new BaseCalendar(Calendar.getInstance().getTimeZone()), 10);
trigger = trigger.getTriggerBuilder().endAt(endDate).build();
If this won't work, then as said here and here, you can't set a repeat count, and you should use TriggerListener.
In any case, version 2.2 doesn't have this feature.
Update
I've tested it, and it works.
Wy dont't you instead use the Simple Trigger? You would have the additional taks of calculating the time interval at the time of scheduling the job, but that will be a one time activity.
I'm new to Quartz in java and I have a question regarding misfiring.
I have set up a SimpleTrigger which fires every 5 seconds. Sometimes the associated job takes over 5 seconds. I'd like to skip the job when that happens (the set interval has been reached by the Trigger). Going through the API I dont find a misfiring policy that would do that.
Any toughts?
Thank you for the help
There are a couple of different misfire policies that could work for you. Look at the javadocs here: http://www.quartz-scheduler.org/docs/api/1.8.0/org/quartz/SimpleTrigger.html paying attention to the static final constants that start with MISFIRE_INSTRUCTION_RESCHEDULE_*. There are a number of different behaviors in regards to the repeat count, but I think they'll accomplish what you're trying to do.
I am using Jboss5.1.x, EJB3.0, Quartz 1.8
I have System which is being activated at specific time(surrounding that time).
The system should work once in a day.
I am setting value in a database which mention the activation time and every hour the system is pulling that value to check if the current time is matching the value (in case it is the system will activate itself).
This time has to be changeable in the future dynamiclly.
Now this technic gives me a headache, since I need to do some Math calculations (in case the current time has passed in couple of mins I still need to activate the system.
more over I need to take care for a case the system already activated so it wont be activated again in the same day (due to a time mistake caluclations.)
I could think about other technic which pulling the database once in couple of days to check if the activiation time has ever change(in this case I wont need to pull every hour, but in other case i am not sure Quartz can re-schedualre it's triggers while it's running)
any ideas? solutions?
Thanks,
ray.
You absolutely can reschedule triggers while Quartz is running (or add new triggers).
You can even do that from within the executing jobs if you like.
This a great example for my solution:
Dynamic time scheduling advice
I am building an app for which I need to set up cron jobs. What I want to do is to set the specific minutes in a hour where specific crons should run. For instance:
Task1 at 1st minute of the hour
Task2 on every second minute of the hour
Task3 every 2 minute only in the second half of the hour
Building this in the standard Unix cron format is reasonably straightforward, but could not figure out how to do it in the Google-App-Engine.
The documentation does not list any non-trivial examples. Any suggestions on how to do it? Examples would be excellent.
The documentation you linked to seems to indicate that it isn't possible to do what you want using only Cron for Java (unless they have an undocumented feature for it). In particular this doesn't appear to allow for multiple times.
time specifies the time of day, as HH:MM in 24 hour time.
The Python version says the exact same thing.
However, one solution (albeit somewhat more expensive in terms of CPU usage) would be to call a URL every minute, and from the handler for that URL, dispatch out to whatever other calls you need.
In other words, something like:
<?xml version="1.0" encoding="UTF-8"?>
<cronentries>
<cron>
<url>/run-scheduled-tasks</url>
<description>Run all scheduled tasks</description>
<schedule>every 1 minutes</schedule>
</cron>
</cronentries>
Then in run-scheduled-tasks, check a database for when each task last run, and if your complex condition for triggering them has occurred since then.
If the documentation is correct you can't get as granular as you are wanting. Doesn't look like they support picking a particular minute of the hour. Or a subset of an hour.
You might have to get creative. Why do you need such specific timing?
This may seem silly. Write three servlet. And schedule them from another UNIX machine on the other part of the world :D. Or even you can write a java app to do it. enjoy
Have a look at Quartz and see if that'll solve your problem.