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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13835221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 05:35:39  来源:igfitidea点击:

Quartz: Cron expression that will never execute

springquartz-scheduler

提问by Chop

I know there is a duplicate here, which probably is exactly my case, though it would deserve some better explanation, which I will try to provide here.

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

I work with a Java web application using a Spring application context. In this context, I defined scheduled jobs using Quartz. These jobs are triggered by a cron defined in a .properties file.

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

The Spring context is embedded within the war, while the .properties file is on the application server (Tomcat in this particular case).

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

This is just fine and allows to define different crons according to the environment (development, integration, production, ...).

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

Now, when running this application locally on my own computer, I do not wish these jobs to be executed. Is there a way to write a cron expression which will never trigger?

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

采纳答案by Chop

TL;DR

TL; 博士

In Quartz 1, you may use this cron: 59 59 23 31 12 ? 2099(last valid date).
In Quartz 2, you may use this cron: 0 0 0 1 1 ? 2200

在 Quartz 1 中,你可以使用这个 cron:(59 59 23 31 12 ? 2099最后一个有效日期)。
在 Quartz 2 中,你可以使用这个 cron:0 0 0 1 1 ? 2200

Using an expression far in the future

在很远的将来使用表达式

Made some quick tests using org.quartz.CronExpression.

使用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()));
}

When I do String exp = "# 0 0 0 1 1 ?";, the isValidtest returns false.

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

With the sample given above yet, the output is the following:

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

true
null

Meaning:

意义:

  • the expression is valid;
  • there is no upcoming date which matches this expression.
  • 表达式有效;
  • 没有与此表达式匹配的即将到来的日期。

For the scheduler to accept a cron trigger, though, the latter mustmatch a date in the future.

但是,为了让调度程序接受 cron 触发器,后者必须匹配未来的日期。

I tried several years and figured out that once the year is above 2300, Quartz seems not to bother anymore (though I did not find a mention to a maximal value for the year in Quartz 2's documentation). There might be a cleaner way to do this, but this will satisfy my needs for now.

我尝试了几年并发现一旦年份超过 2300,Quartz 似乎不再打扰(尽管我没有在 Quartz 2 的文档中找到提及年份的最大值)。可能有一种更清洁的方法来做到这一点,但这将满足我现在的需求。

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

所以,最后,我建议的 cron 是0 0 0 1 1 ? 2200.

Quartz 1 variant

石英 1 变体

Note that, in Quartz 1, 2099 is the last valid year. You can therefore adapt your cron expression to use Maciej Matys's suggestion: 59 59 23 31 12 ? 2099

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

Alternative: Using a date in the past

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

Arnaud Denoyellesuggested something more elegant, which my test above validates as a correct expression: instead of choosing a date in a far future, choose it in a far past:

Arnaud Denoyelle提出了一些更优雅的建议,我上面的测试证明这是一个正确的表达方式:与其选择遥远的未来,不如选择遥远的过去:

0 0 0 1 1 ? 1970(the first valid expression according to Quartz documentation).

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

This solution does not work though.

但是,此解决方案不起作用。

hippofluffhighlighted that Quartz will detect an expression in past will never be executed again and therefore throw an exception.

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

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

This seems to have been in Quartz for a long time.

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

Lessons learned: the test is not foolproof as is

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

This highlights a weakness of my test: in case you want to test a CronExpression, remember it has to have a nextValidTime1. Otherwise, the scheduler you will pass it to will simply reject it with the above mentioned exception.

这突出了我的测试的一个弱点:如果你想测试 a CronExpression,记住它必须有一个nextValidTime1。否则,您将其传递给的调度程序将简单地拒绝它,并出现上述异常。

I would advise adapting the test code as follows:

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

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."));

There you go: no need to think, just read the output.

你去吧:无需思考,只需阅读输出。



1This is the part I forgot when testing Arnaud's solution making me the fool and proving my test wasn't me-proof.

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

回答by Eric Tjossem

Technically, valid values for the optional Quartz year field are 1970-2099, so 2300 isn't an expected value. I'm assuming you reallyneed to do this and your version of Quartz attempts to enforce valid cron syntax (day 1-31, month 1-12, and so on).

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

I'm currently using the following code in Resque-scheduler for Rails, which accepts schedule info in validated crontab format, to create a manual-run-only test job:

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

cron: "0 5 31 2 *"

The job will wait patiently for early morning February 31stbefore running. For an equivalent in Quartz crontrigger, try this line or some variant thereof:

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

0 0 5 31 2 ?

回答by Maciej Matys

Give a try to this one: 59 59 23 31 12 ? 2099

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

回答by mrmoosehead

I found this whilst trying to solve a similar problem - disabling a cron expression - but ran into the same problems of requiring a valid future schedule date.

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

I also hit problems using the 7 value syntax - cannot specify a year in the cron schedule.

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

So I used this: 0 0 3 ? 2 MON#5

所以我用了这个: 0 0 3 ?2 星期一#5

The next times this will execute are:

这将执行的下一次是:

  1. Monday, February 29, 2044 3:00 AM
  2. Monday, February 29, 2072 3:00 AM
  3. Monday, February 29, 2112 3:00 AM
  4. Monday, February 29, 2140 3:00 AM
  5. Monday, February 29, 2168 3:00 AM
  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

So, essentially, to all intents and purposes, it's disabled. :)

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

Ah. Curses, this will only work for Quartz scheduler syntax - Spring CronTrigger syntax doesn't allow MON#5 for the fifth monday

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

So the next best thing is 0 0 3 29 2 ? which will only execute at 3am on the 29th Feb (leap years)

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

回答by icyerasor

If you're using the expression in a @Scheduled(cron="")expression (technically not using quartz, but rather common with spring those days) you can not use the 7-field year-in-the-future solution but those options:

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

  • If you're using spring 5.1+ (springBoot 2.1+) simply use "${your.cron.prop:-}and don't set the property to disable execution - see @Scheduled. Or set the property itself to "-" (make sure to use quotes if you're using a yml).
  • Disable the bean/service with the @Scheduledmethod altogether, for example by using a @ConditionalOnProperty("my.scheduleproperty.active")annotation and not setting the property (or setting it to false)
  • 如果您使用的是 spring 5.1+ (springBoot 2.1+),只需使用"${your.cron.prop:-}并且不要将属性设置为禁用执行 - 请参阅@Scheduled。或者将属性本身设置为“-”(如果您使用的是 yml,请确保使用引号)。
  • 使用该@Scheduled方法完全禁用 bean/服务,例如通过使用@ConditionalOnProperty("my.scheduleproperty.active")注释而不设置属性(或将其设置为false

回答by Stephane Nicoll

Now, when running this application locally on my own computer, I do not wish these jobs to be executed. Is there a way to write a cron expression which will never trigger?

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

If you want to disable scheduling on your computer, you have several ways to make that happen.

如果您想在您的计算机上禁用日程安排,您有多种方法可以实现这一点。

First you could move the configuration of Quartz to a @Profile-based configuration and not enable this profile locally. Quartz wouldn't start at all if the profile is not active.

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

An alternative is to configure Quartz to not start automatically. There is a SchedulerFactoryBean#setAutoStartup()that you can set in BeanPostProcessorregistered in a dev profile. While this thread is quite old, Spring Boot offers an alternative by registering a SchedulerFactoryBeanCustomizerbean to do the same thing.

另一种方法是将 Quartz 配置为不自动启动。还有一个SchedulerFactoryBean#setAutoStartup(),你可以在设置BeanPostProcessor中的一个开发的个人资料登记。虽然这个线程已经很老了,但 Spring Boot 提供了一种替代方案,即注册一个SchedulerFactoryBeanCustomizerbean 来做同样的事情。

回答by Pallav Chanana

Hi you can try this it will never execute your schedular just pass as -in cron

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

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

schedular.cron.expression=-