web-dev-qa-db-ja.com

クォーツ:実行されないCron式

here が重複していることは知っていますが、これはおそらくまさに私の場合です。

Springアプリケーションコンテキストを使用して、Java Webアプリケーションを操作します。このコンテキストでは、Quartzを使用してスケジュールされたジョブを定義しました。これらのジョブは、.propertiesファイルで定義されたcronによってトリガーされます。

Springコンテキストはwar内に埋め込まれていますが、.propertiesファイルはアプリケーションサーバー(この特定の場合はTomcat)上にあります。

これは問題なく、環境(開発、統合、生産など)に応じて異なるcronを定義できます。

現在、このアプリケーションを自分のコンピューターでローカルに実行するとき、これらのジョブが実行されることは望みません。トリガーしないcron式を記述する方法はありますか?

71
Chop

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トリガーを受け入れるには、後者mustが将来の日付に一致する必要があります。

私は数年試してみましたが、年が2300を超えると、Quartzはもう気にしないようです(ただし、その年の最大値についての言及は見つかりませんでした Quartz 2のドキュメント )。これを行うためのよりクリーンな方法があるかもしれませんが、これは今のところ私のニーズを満たすでしょう。

だから、最終的に、私が提案するcronは0 0 0 1 1 ? 2200です。

クォーツ1バリアント

Quartz 1では、 2099は最後の有効な年 であることに注意してください。したがって、 Maciej Matysの提案59 59 23 31 12 ? 2099を使用するようにcron式を調整できます。

代替:過去の日付を使用する

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にあったようです 長い間

学んだ教訓:テストはそのままでは万全ではない

これは私のテストの弱点を浮き彫りにします: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のソリューションをテストして私を馬鹿にし、テストが私の証拠ではなかったことを証明するときに忘れていた部分です。

62
Chop

技術的には、オプションのQuartz年フィールドの有効な値は1970〜2099であるため、2300は期待値ではありません。私はあなたが本当にこれを行う必要があり、Quartzのバージョンが有効なcron構文を強制しようとすると仮定しています等々)。

現在、Resque-scheduler for Railsで次のコードを使用しています。これは、検証済みのcrontab形式のスケジュール情報を受け入れ、手動実行のみのテストジョブを作成します。

cron: "0 5 31 2 *"

ジョブは、実行する前に早朝 2月31日 を辛抱強く待ちます。 Quartz crontrigger の同等のものについては、次の行またはその変形を試してください。

0 0 5 31 2 ?
36
Eric Tjossem

これを試してください:59 59 23 31 12 ? 2099

25
Maciej Matys

同様の問題-cron式を無効にする-を解決しようとしたときにこれを見つけましたが、有効な将来のスケジュール日付を要求するという同じ問題に遭遇しました。

また、7つの値の構文を使用して問題が発生しました-cronスケジュールで年を指定できません。

だから私はこれを使用しました:0 0 3? 2 MON#5

次に実行されるのは次のとおりです。

  1. 2044年2月29日月曜日午前3時
  2. 2072年2月29日月曜日午前3時
  3. 2112年2月29日(月曜日)午前3時00分
  4. 2140年2月29日(月曜日)午前3時
  5. 2168年2月29日(月曜日)午前3時

したがって、本質的に、すべての意図と目的に対して、無効になっています。 :)

あ。 Curses、これはQuartzスケジューラー構文でのみ機能します-Spring CronTrigger構文は、5番目の月曜日にMON#5を許可しません

したがって、次善の策は0 0 3 29 2です。 2月29日(うるう年)の午前3時にのみ実行されます。

6
mrmoosehead

現在、このアプリケーションを自分のコンピューターでローカルに実行するとき、これらのジョブが実行されることは望みません。トリガーしないcron式を記述する方法はありますか?

コンピューターでスケジュールを無効にする場合、いくつかの方法でそれを実現できます。

最初に、Quartzの構成を@Profileベースの構成に移動し、このプロファイルをローカルで有効にしないでください。プロファイルがアクティブでない場合、Quartzはまったく起動しません。

別の方法は、Quartzが自動的に起動しないように構成することです。 devプロファイルに登録されているBeanPostProcessorに設定できるSchedulerFactoryBean#setAutoStartup()があります。このスレッドは非常に古いものですが、Spring BootはSchedulerFactoryBeanCustomizer Beanを登録して同じことを行う代替手段を提供します。

2
Stephane Nicoll

@Scheduled(cron="")式で式を使用している場合(技術的にはクォーツを使用せず、むしろ春によく使用されます)、7フィールドの将来のソリューションではなく、これらのオプションを使用できます。

  • Spring 5.1+(springBoot 2.1+)を使用している場合は、単に"${your.cron.prop:-}を使用し、プロパティを無効に設定しないでください- @ Scheduled を参照してください
  • たとえば@ConditionalOnProperty("my.scheduleproperty.active")アノテーションを使用し、プロパティを設定しない(またはfalseに設定する)ことにより、@Scheduledメソッドを使用してBean /サービスを無効にします。
1
icyerasor