93

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

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

Spring 上下文嵌入在 war 中,而 .properties 文件位于应用程序服务器上(在本例中为 Tomcat)。

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

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

4

8 回答 8

82

TL;博士

在 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 似乎不再打扰(尽管我在 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.

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

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

这突出了我的测试的一个弱点:如果你想测试 a 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."));

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


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

于 2012-12-12T09:43:47.020 回答
44

从技术上讲,可选 Quartz 年份字段的有效值为 1970-2099,因此 2300 不是预期值。我假设您确实需要这样做,并且您的 Quartz 版本尝试强制执行有效的 cron 语法(第 1-31 天、第 1-12 个月等)。

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

cron: "0 5 31 2 *"

该作业将耐心等待2 月 31日凌晨,然后再运行。对于Quartz crontrigger中的等效项,请尝试此行或其一些变体:

0 0 5 31 2 ?
于 2012-12-18T17:12:44.660 回答
25

试试这个:59 59 23 31 12 ? 2099

于 2013-02-06T15:45:46.853 回答
10

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

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

我在尝试解决类似问题时发现了这一点 - 禁用 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

因此,从本质上讲,就所有意图和目的而言,它已被禁用。:)

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

所以下一个最好的事情是 0 0 3 29 2 ?仅在 2 月 29 日(闰年)凌晨 3 点执行

于 2018-01-10T08:56:57.493 回答
5

嗨,你可以试试这个它永远不会执行你的计划,就像-在 cron 中一样通过

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

schedular.cron.expression=-
于 2020-05-27T09:35:37.147 回答
2

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

如果您想在您的计算机上禁用计划,您有几种方法可以做到这一点。

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

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

于 2018-08-08T09:42:37.290 回答
-1

对任何天数少于此天数的月份使用 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_上进行验证*

于 2021-06-29T12:45:50.367 回答