8

我已经为 Spring 设置@Scheduled了每小时的 cron 表达式,如下所示 where trend.olap.local.loading.cron.expressionis 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);
    }
}

在这里,我的意图是从当前日期和时间获取小时值并将其传递给 executor 方法。

基本上,我将当前小时减去 1,以便在 17:00 时,小时值应为 16。

但是如果您查看日志,则小时值是 15。这是因为调度程序在 16:59:59,831 左右运行。请参阅下面的 log4j 日志。看起来 cron 作业正在四舍五入毫秒并在 17:00:00,000 之前几毫秒被触发。

正因为如此,我得到了错误的价值观,我的商业案例失败了。

如何使 cron 在每小时的第 0 毫秒而不是几毫秒之前精确运行?

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.
4

3 回答 3

4

简短的回答是您不能选择该cron选项。cron 表达式的分辨率是秒,所以它会四舍五入到最接近的秒。您可以保证它至少在特定时间之后发生,但不能完全在 cron 上发生。

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

于 2014-08-19T16:39:40.270 回答
1

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

尽管您可以改为调整 cron 时间表,但我觉得这更像是一种 hack,而不是在代码中处理它,因为此时您正在逼近一个近似值。您可以更好地控制代码来处理超过一百毫秒的偏移量

于 2014-08-23T00:19:37.030 回答
0

Cron 将忽略毫秒,并且暗示只能精确到一秒钟,假设没有任何其他时间问题,例如系统上的突然负载。

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

在这两者中,第一个是最简单的,我认为它比在使用浮点数时允许舍入问题更骇人听闻。

于 2014-08-21T20:49:30.437 回答