Spring的@Scheduled cron作业在预定时间之前触发了几毫秒

PSh*_*tty 8 java cron spring spring-scheduled

我已经安装春天的@Scheduled有如下其中一个cron表达式,每隔一小时trend.olap.local.loading.cron.expression0 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这里我的目的是从当前日期和时间获取小时值并将其传递给执行程序方法.

基本上我采取当前小时减1,所以在17:00,小时值应该是16.

但是如果你看到日志,则小时值为15.这是因为调度程序运行在16:59:59,831左右.请参阅下面的log4j日志.看起来cron作业在几毫秒内完成并在17:00:00,000之前几毫秒触发.

因此,我得到了错误的价值观,而我的商业案例也失败了.

如何让cron在每小时的零毫秒内完全运行,而不是在几毫秒之前?

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.
Run Code Online (Sandbox Code Playgroud)

Mic*_*lla 6

简短的回答是你不能使用这个cron选项。cron 表达式的分辨率是秒,因此它将四舍五入到最接近的秒。您也许能够保证它至少在特定时间之后发生,但不能完全用 cron 来保证。

你最好的选择是实施你自己的Trigger。该Trigger接口有一个方法返回java.util.Date下一次执行的 时间(以毫秒为单位)。从那里您可以注册任务和触发器,如文档中所示:http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableScheduling.html