1. ホーム
  2. spring

[解決済み] クオーツ 決して実行されないCron式

2023-02-28 19:23:37

質問

重複している はこちら は、おそらくまさに私のケースですが、より良い説明に値すると思いますので、ここで提供しようと思います。

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

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

これはちょうどよく、環境(開発、統合、本番、...)に応じて異なるクーロンを定義することができます。

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

どのように解決するのですか?

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 はもう気にしないようだとわかりました (ただし、年の最大値への言及は見つかりませんでした)。 の最大値についての言及は見つかりませんでしたが、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のドキュメントによると、最初の有効な表現)。

しかし、この解決策はうまくいきません。

ヒッポフラフ は、Quartz が過去の式が二度と実行されないことを検出し、例外をスローすることを強調しました。

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

これはQuartzにあったようです で長い間 .

教訓:テストはそのままでは誤魔化せない

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