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

时间:2013-09-29 12:59:00

标签: java spring cron spring-scheduled

我已经设置了Spring的@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);
    }
}

这里我的目的是从当前日期和时间中取出小时值并将其传递给执行者方法。

基本上我当前小时减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.

3 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:1)

如果您打算插入正确的小时值,我认为更好的解决方案是根据较不可预测的cron计划计算小时数。只要它落在一秒钟之内,您就可以简单地获取当前时间并将其转换为最接近的小时,然后从那里获取小时值。您还可以添加警告/警报,通过收听迟到超过一分钟或迟到10分钟等的任务,让您知道cron是否表现不稳定。

虽然您可以改为调整cron时间表,但我觉得这比在代码中处理它更具攻击性,因为您在此时接近近似值。您可以在代码中拥有更多控制权来处理超过100毫秒的简单偏移量

答案 2 :(得分:0)

Cron将忽略毫秒,并且暗示只有在一秒钟内才准确,假设没有任何其他时序问题,例如系统突然加载。

您有两个选择: 1.一小时后启动cron作业几秒钟 2.更改小时计算以允许提前触发作业。

在这两个中,第一个是最简单的,我不会把它称为比使用浮点数时允许舍入问题更黑客。