首页 文章

Quartz:永远不会执行的Cron表达式

提问于
浏览
63

我知道有一个重复的here,这可能就是我的情况,虽然它应该得到一些更好的解释,我将在这里尝试提供 .

我使用Spring应用程序上下文使用Java Web应用程序 . 在这种情况下,我使用Quartz定义了预定作业 . 这些作业由.properties文件中定义的cron触发 .

Spring上下文嵌入在war中,而.properties文件位于应用程序服务器上(在这种特殊情况下为Tomcat) .

这很好,允许根据环境(开发,集成, 生产环境 ......)定义不同的crons .

现在,在我自己的计算机上本地运行此应用程序时,我不希望执行这些作业 . 有没有办法写一个永远不会触发的cron表达式?

5 回答

  • 25

    我在尝试解决类似问题时发现了这一点 - 禁用cron表达式 - 但遇到了需要有效的未来计划日期的相同问题 .

    我还使用7值语法遇到问题 - 无法在cron计划中指定年份 .

    所以我用过这个:0 0 3? 2周一#5

    这将执行的下一次是:

    • 2044年2月29日星期一凌晨3:00

    • 2072年2月29日星期一凌晨3:00

    • 星期一,2112年2月29日凌晨3:00

    • 2140年2月29日星期一凌晨3:00

    • 2168年2月29日星期一凌晨3:00

    因此,基本上,对于所有意图和目的,它都是禁用的 . :)

    啊 . Curses,这只适用于Quartz调度程序语法 - Spring CronTrigger语法不允许第五个星期一的MON#5

    那么下一个最好的事情是0 0 3 29 2?只会在2月29日凌晨3点(闰年)执行

  • 36

    尝试一下这个: 59 59 23 31 12 ? 2099

  • 50

    现在,在我自己的计算机上本地运行此应用程序时,我不希望执行这些作业 . 有没有办法写一个永远不会触发的cron表达式?

    如果要禁用计算机上的计划,可以通过多种方法实现此目的 .

    首先,您可以将Quartz的配置移动到基于 @Profile 的配置,而不是在本地启用此配置文件 . 如果配置文件未激活,则Quartz根本不会启动 .

    另一种方法是将Quartz配置为不自动启动 . 您可以在 BeanPostProcessor 中设置 SchedulerFactoryBean#setAutoStartup() ,在开发配置文件中注册 . 虽然这个线程很老,但是Spring Boot通过注册一个 SchedulerFactoryBeanCustomizer bean来做同样的事情 .

  • 5

    从技术上讲,可选的Quartz year字段的有效值是1970-2099,因此2300 isn 't an expected value. I' m假设你确实需要这样做,并且你的Quartz版本试图强制执行有效的cron语法(第1-31天,第1-12天,和等等) .

    我目前在Resque-scheduler for Rails中使用以下代码,它接受以经过验证的crontab格式的计划信息,以创建仅手动运行的测试作业:

    cron: "0 5 31 2 *"
    

    在跑步之前,这份工作将耐心等待清晨February 31st . 对于Quartz crontrigger中的等效项,请尝试以下行或其中的一些变体:

    0 0 5 31 2 ?
    
  • 2

    TL; DR

    在Quartz 1中,您可以使用此cron: 59 59 23 31 12 ? 2099 (上一个有效日期) .
    在Quartz 2中,您可以使用此cron: 0 0 0 1 1 ? 2200

    将来使用表达式

    使用 org.quartz.CronExpression 进行了一些快速测试 .

    String exp = "0 0 0 1 1 ? 3000";
    boolean valid = CronExpression.isValidExpression(exp);
    System.out.println(valid);
    if (valid) {
        CronExpression cronExpression = new CronExpression(exp);
        System.out.println(cronExpression.getNextValidTimeAfter(new Date()));
    }
    

    当我执行 String exp = "# 0 0 0 1 1 ?"; 时, isValid 测试返回 false .

    使用上面给出的示例,输出如下:

    true
    null
    

    含义:

    • 表达式有效;

    • 没有与此表达式匹配的即将到来的日期 .

    但是,要使调度程序接受cron触发器,后者必须与将来的日期匹配 .

    我试了几年,发现一旦年度超过2300,Quartz似乎不再烦恼了(尽管我没有找到年度最大值in Quartz 2's documentation) . 可能有更简洁的方法来做到这一点,但这将满足我现在的需求 .

    So, in the end, the cron I propose is 0 0 0 1 1 ? 2200.

    Quartz 1变种

    请注意,在Quartz 1中,2099 is the last valid year . 因此,您可以调整您的cron表达式以使用Maciej Matys's suggestion59 59 23 31 12 ? 2099

    替代方案:使用过去的日期

    Arnaud Denoyelle建议更优雅的东西,我上面的测试验证为正确的表达:不是在遥远的未来选择一个日期,而是选择它远在过去:

    0 0 0 1 1 ? 1970 (根据Quartz文档的第一个有效表达式) .

    This solution does not work though.

    hippofluff突出显示Quartz将检测过去的表达式永远不会再次执行,因此抛出异常 .

    org.quartz.SchedulerException: Based on configured schedule, the given trigger will never fire.
    

    这似乎是在Quartz for a long time中 .

    经验教训:测试并非万无一失

    这突出了我的测试的弱点:如果你想测试 CronExpression ,请记住 it has to have a nextValidTime 1.否则,你将传递给它的调度程序将简单地拒绝它与上述异常 .

    我建议如下调整测试代码:

    String exp = "0 0 0 1 1 ? 3000";
    boolean valid = CronExpression.isValidExpression(exp);
    if (valid) {
        CronExpression cronExpression = new CronExpression(exp);
        valid = cronExpression.getNextValidTimeAfter(new Date()) != null;
    }
    System.out.println("Can I use <" + exp + ">? " + (valid ? "Go ahead!" : "This shall fail."));
    

    你去了:不需要思考,只需阅读输出 .


    1这是我在测试Arnaud的解决方案时忘记的部分,这使我成为傻瓜和证明我的测试不是我的证明 .

相关问题