I have setup Spring's @Scheduled
with a cron expression for every hour as below where trend.olap.local.loading.cron.expression
is 0 0 * * * ?
.
@Scheduled(cron = "${trend.olap.local.loading.cron.expression}")
public void loadHoulyDataToLocalOlap() {
try {
// To calculate prev hour;
Calendar cal = Calendar.getInstance();
cal.add(Calendar.HOUR, -1);
Date date = cal.getTime();
int hour = cal.get(Calendar.HOUR_OF_DAY);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Loading hourly data into local olap :" + date
+ ", and hour :" + hour);
}
dataIntegrationProcessor.loadHourlyDataToLocalOlap(hour);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Loading hourly data into local olap :" + date
+ ", and hour :" + hour + " Completed.");
}
} catch (Exception e) {
LOGGER.error("Error occured at loadHoulyDataToLocalOlap", e);
}
}
Here my intent is to take the hour value from current date and time and pass it to executor methods.
Basically I am taking current hour minus one so that at 17:00, the hour value should be 16.
But if you see the logs, the hour value is 15. This is because the Scheduler ran at around 16:59:59,831. See the log4j logs below. It Looks like the cron job is rounding off the milliseconds and getting triggered a few milliseconds before 17:00:00,000.
Because of this, I am getting wrong values and my business case is failing.
How do I make the cron run exactly at the zero'th milliseconds for every hour, instead of few milliseconds before?
DEBUG 2013-09-29 16:59:59,831 (TrendScheduler.java loadHoulyDataToLocalOlap:57) - Loading hourly data into local olap :Sun Sep 29 15:59:59 IST 2013, and hour :15
DEBUG 2013-09-29 16:59:59,831 (DataIntegrationProcessor.java loadHourlyDataToLocalOlap:57) - Loading hourly data for hour :15
INFO 2013-09-29 17:00:00,054 (KettleJobExecutor.java executeJob:73) - Job (24hr_populate_hour_data_job.kjb) executed successfully
DEBUG 2013-09-29 17:00:00,054 (TrendScheduler.java loadHoulyDataToLocalOlap:64) - Loading hourly data into local olap :Sun Sep 29 15:59:59 IST 2013, and hour :15 Completed.
The short answer is that you can't with the cron
option. The resolution of the cron expressions is to the second so it's going to round to the nearest second. You may be able to guarantee that it happens at least after the specific time but not exactly on it with cron.
Your best bet would be to implement your own Trigger
. The Trigger
interface has a single method that returns the java.util.Date
for the next execution (which is in milliseconds). From there you can register the task and trigger as shown in the documentation here: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableScheduling.html
If you intent is to insert the correct hour value, the I think better solution would be to calculate the hour based on the less predictable cron schedule. As long as it falls within a second, you could simply get currenttime and convert it to the nearest hour, and then derive the hour value from there. You could also add warnings/alerts to let you know if the cron is behaving erratic by listening in on tasks that start more than a minute late, or 10 minutes late, etc.
Although you could adjust the cron schedule instead, I feel that's more of a hack than handling it in code since you are approximating an approximation at that point. You have more control in code to handle more than a simple hundred millisecond offset
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With