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

时间:2012-12-12 07:56:12

标签: spring quartz-scheduler

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

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

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

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

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

8 个答案:

答案 0 :(得分:59)

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)。可能有一种更简洁的方法,但这将满足我现在的需求。

所以,最后,我建议的cron是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文档的第一个有效表达式)。

此解决方案不起作用。

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

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

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

经验教训:测试不是万无一失的

这凸显了我的测试的弱点:如果您想测试CronExpression,请记住它必须有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解决方案时忘记的部分让我变得愚蠢,证明我的测试不是我的证明。

答案 1 :(得分:36)

从技术上讲,可选的Quartz year字段的有效值是1970-2099,因此2300不是预期值。我假设你真的需要这样做,你的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 :(得分:25)

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

答案 3 :(得分:6)

我在尝试解决类似问题时发现了这一点 - 禁用了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
  6. 因此,基本上,对于所有意图和目的,它都是禁用的。 :)

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

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

答案 4 :(得分:2)

  

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

如果要在计算机上禁用计划,则有几种方法可以实现。

首先,您可以将Quartz的配置移至基于@Profile的配置,而不在本地启用此配置文件。如果配置文件未激活,Quartz根本无法启动。

另一种方法是将Quartz配置为不自动启动。您可以在开发配置文件中注册的SchedulerFactoryBean#setAutoStartup()中设置一个BeanPostProcessor。尽管该线程已经很老了,但Spring Boot通过注册SchedulerFactoryBeanCustomizer bean来提供相同的功能,从而提供了另一种选择。

答案 5 :(得分:1)

如果您在@Scheduled(cron="")表达式中使用该表达式(技术上不使用石英,而在那些春季相当普遍),则不能使用7字段的年度解决方案,但是选项:

  • 如果您使用的是Spring 5.1+(springBoot 2.1+),则只需使用"${your.cron.prop:-}并且不要将属性设置为disable-请参见@Scheduled
  • 例如,通过使用@Scheduled注释而不设置属性(或将其设置为@ConditionalOnProperty("my.scheduleproperty.active")),完全使用false方法禁用bean /服务。

答案 6 :(得分:1)

嗨,您可以尝试执行此操作,它将永远不会执行您的计划 只需在{}中作为-传递

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

schedular.cron.expression=-

答案 7 :(得分:0)

对于天数少于此值的任何月份,请使用 31。 因此,0 0 31 2 * for February0 0 31 5 * for May 0 0 31 6 for June * 0 0 31 9 * for September 0 0 31 11 * for November

应该防止 cron 执行。 这些是有效的 cron 表达式,可以在 https://crontab.guru/#0_0_31_2_*