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

Cho*_*hop 74 spring quartz-scheduler

我知道有一个重复这里,这可能正是我的情况下,虽然它会值得一些更好的解释,我会尝试在这里提供.

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

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

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

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

Cho*_*hop 66

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

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

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

true
null
Run Code Online (Sandbox Code Playgroud)

含义:

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

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

我试了几年,并发现一旦年度超过2300,Quartz似乎不再烦了(虽然我没有在Quartz 2的文档中找到年度最大值).可能有更简洁的方法来做到这一点,但这将满足我现在的需求.

所以,最后,我提出的cron是0 0 0 1 1 ? 2200.

石英1变种

请注意,在Quartz 1中,2099是最后一个有效年份.因此,您可以调整您的cron表达式以使用Maciej Matys的建议:59 59 23 31 12 ? 2099

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

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

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

这个解决方案不起作用.

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

org.quartz.SchedulerException: Based on configured schedule, the given trigger will never fire.
Run Code Online (Sandbox Code Playgroud)

这似乎已经在Quartz中存在了很长时间.

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

这凸显了我测试的弱点:如果你想测试一个CronExpression,记住它必须有nextValidTime1.否则,您将传递给它的调度程序将仅使用上述异常拒绝它.

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

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

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


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

  • Quartz 2.1.0抛出SchedulerException"根据配置的调度,给定的触发器永远不会文件",并且在使用Arnaud的建议时,我的Grails应用程序启动失败 (5认同)
  • 为什么不是'0 0 0 1 1?1970`?Quartz会拒绝吗? (3认同)
  • 没有必要感觉到,谢谢你更新答案!+1 :)仅供参考,未来约会的允许时间为100年.任何计划在未来超过100年的事情都将无法安排.不知道为什么他们定居100年,但如果一个应用程序实际运行足够长的触发,我会非常印象大声笑.尽管如此,如果这种技术在100年内就已为人所知 (2认同)
  • 我检查代码[1]是否为年份的魔术值(2200对我失败)(javadoc [2]表示2199是最大值,教程[3]表示2099是最大值).实际的最大值是:public static final int MAX_YEAR = Calendar.getInstance().get(Calendar.YEAR)+ 100; 所以今年的最大值是2116,明年的最大值是2117 [1] https://fisheye.terracotta.org/browse/Quartz/trunk/quartz-core/src/main/java/org/quartz/CronExpression.java? r = 2426#to257 [2] http://quartz-scheduler.org/api/2.2.1/org/quartz/CronExpression.html [3] http://quartz-scheduler.org/documentation/quartz-2. X /教程/ crontrigger (2认同)

Eri*_*sem 36

从技术上讲,可选的Quartz year字段的有效值是1970-2099,因此2300不是预期值.我假设你真的需要这样做,你的Quartz版本试图强制执行有效的cron语法(第1-31天,第1-12个月,依此类推).

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

cron: "0 5 31 2 *"
Run Code Online (Sandbox Code Playgroud)

这项工作将耐心等待2月31日凌晨,然后再开始运行.对于Quartz crontrigger中的等效,请尝试以下行或其中的一些变体:

0 0 5 31 2 ?
Run Code Online (Sandbox Code Playgroud)

  • 哼,终于有机会来测试这个提议.似乎Quartz拒绝了这个cron,因为它检测到它永远不会执行... (9认同)
  • 这不适用于错误"无效的cron表达式"0 0 5 31 2?" 导致失控搜索下一个触发器 (3认同)

Mac*_*tys 25

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

  • 这是最后一个有效的Quartz表达式,你的Quartz拒绝开始工作至少Quartz 1.6和spring 2.5.6SEC3 (11认同)

小智 19

您好,您可以尝试这个,它永远不会执行您的计划,只是像-cron 中那样传递

 @Scheduled(cron = "${schedular.cron.expression}")

schedular.cron.expression=-
Run Code Online (Sandbox Code Playgroud)


icy*_*sor 9

如果您在表达式中使用@Scheduled(cron="")表达式(技术上不使用石英,但在那些日子里很常见),您不能使用 7-field year-in-the-future 解决方案,但这些选项:

  • 如果您使用的是 spring 5.1+ (springBoot 2.1+),只需使用"${your.cron.prop:-}并且不要将属性设置为禁用执行 - 请参阅@Scheduled。或者将属性本身设置为“-”(如果您使用的是 yml,请确保使用引号)。
  • 使用该@Scheduled方法完全禁用 bean/服务,例如通过使用@ConditionalOnProperty("my.scheduleproperty.active")注释而不设置属性(或将其设置为false


mrm*_*ead 7

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

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

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

这将执行的下一次是:

  1. 2044年2月29日星期一凌晨3:00
  2. 2072年2月29日星期一凌晨3:00
  3. 星期一,2112年2月29日凌晨3:00
  4. 星期一,2140年2月29日凌晨3:00
  5. 2168年2月29日星期一凌晨3:00

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

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

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