Подтвердить что ты не робот

Кварц: выражение Cron, которое никогда не будет выполнено

Я знаю, что здесь есть дубликат , который, вероятно, является именно моим делом, хотя он заслуживает лучшего объяснения, которое я попытаюсь предоставить здесь.

Я работаю с веб-приложением Java с использованием контекста приложения Spring. В этом контексте я определил запланированные задания с использованием Quartz. Эти задания запускаются cron, определенными в файле .properties.

Контекст Spring встроен в войну, а файл .properties находится на сервере приложений (Tomcat в данном конкретном случае).

Это просто прекрасно и позволяет определять разные кроссы в соответствии с окружающей средой (разработка, интеграция, производство,...).

Теперь, когда я запускаю это приложение локально на своем собственном компьютере, я не хочу, чтобы эти задания выполнялись. Есть ли способ написать выражение cron, которое никогда не будет срабатывать?

4b9b3361

Ответ 1

TL; DR

В Кварце 1 вы можете использовать этот хрон: 59 59 23 31 12? 2099 59 59 23 31 12? 2099 (последняя действительная дата).
В Quartz 2 вы можете использовать этот cron: 0 0 0 1 1? 2200 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, Кварц, похоже, больше не беспокоит (хотя я не нашел упоминания о максимальном значении для года в документации по Кварцу 2). Возможно, есть более чистый способ сделать это, но это удовлетворит мои потребности на данный момент.

Итак, в конце концов, предлагаемый мне cron - 0 0 0 1 1? 2200 0 0 0 1 1? 2200

Кварц 1 вариант

Обратите внимание, что в Кварце 1 2099 год является последним действительным годом. Поэтому вы можете адаптировать свое выражение cron, чтобы использовать предложение Maciej Matys: 59 59 23 31 12? 2099 59 59 23 31 12? 2099

Альтернатива: использование даты в прошлом

Арно Денойель предложил что-то более изящное, которое мой тест выше подтверждает как правильное выражение: вместо выбора даты в далеком будущем, выберите ее в далеком прошлом:

0 0 0 1 1? 1970 0 0 0 1 1? 1970 (первое действительное выражение согласно документации Quartz).

Это решение не работает, хотя.

hippofluff подчеркнул, что Quartz обнаружит, что выражение в прошлом никогда не будет выполнено снова, и поэтому выдает исключение.

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

Это, кажется, было в Кварце в течение долгого времени.

Извлеченные уроки: тест не является надежным, как есть

Это подчеркивает слабость моего теста: если вы хотите протестировать 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, делая меня дураком и доказывая, что мой тест не был для меня доказательством.

Ответ 2

Технически, действительные значения для поля поля Quartz year - 1970-2099, поэтому 2300 не является ожидаемым значением. Я предполагаю, что вам действительно нужно это сделать, и ваша версия Quartz пытается применить действительный синтаксис cron (день 1-31, месяц 1-12 и т.д.).

В настоящее время я использую следующий код в Resque-scheduler для Rails, который принимает информацию о расписании в подтвержденном формате crontab, чтобы создать тестовое задание только для запуска вручную:

cron: "0 5 31 2 *"

Работа будет ждать терпеливо раннего утра 31 февраля перед запуском. Для эквивалента в Quartz crontrigger попробуйте эту строку или ее вариант:

0 0 5 31 2 ?

Ответ 3

Попробуйте это: 59 59 23 31 12 ? 2099

Ответ 4

Я обнаружил это, пытаясь решить аналогичную проблему - отключение выражения cron - но столкнулся с теми же проблемами, что и требование правильной даты расписания в будущем.

Я также столкнулся с проблемами, используя синтаксис 7 значений - не могу указать год в расписании cron.

Поэтому я использовал это: 0 0 3? 2 ПН № 5

В следующий раз это будет выполнено:

  1. Понедельник, 29 февраля 2044 г., 3:00
  2. Понедельник, 29 февраля 2072 г., 3:00
  3. Понедельник, 29 февраля 2112 3:00
  4. Понедельник, 29 февраля 2140 3:00
  5. Понедельник, 29 февраля, 2168, 3:00

Так что, по сути, он, по сути, отключен. :)

Ах. Проклятия, это будет работать только для синтаксиса планировщика Quartz - синтаксис Spring CronTrigger не позволяет использовать MON # 5 для пятого понедельника.

Итак, следующая лучшая вещь - это 0 0 3 29 2? который будет исполнен только в 3 часа ночи 29 февраля (високосные годы)

Ответ 5

Теперь, когда я запускаю это приложение на моем собственном компьютере, я не хочу, чтобы эти задания выполнялись. Есть ли способ написать выражение cron, которое никогда не сработает?

Если вы хотите отключить планирование на своем компьютере, у вас есть несколько способов сделать это.

Сначала вы можете переместить конфигурацию Quartz в конфигурацию @Profile -based и не включать этот профиль локально. Кварц не запустится вообще, если профиль не активен.

Альтернативой является настройка Quartz для автоматического запуска. Существует SchedulerFactoryBean#setAutoStartup() который вы можете установить в BeanPostProcessor зарегистрированном в профиле разработчика. Хотя этот поток довольно старый, Spring Boot предлагает альтернативу, регистрируя bean-компонент SchedulerFactoryBeanCustomizer чтобы сделать то же самое.

Ответ 6

Если вы используете выражение в выражении @Scheduled(cron="") (технически не использующее кварц, а скорее обычное для весны в те дни), вы не можете использовать решение "7 лет в будущем", но те опции:

  • Если вы используете spring 5. 1+ (springBoot 2. 1+) просто используйте "${your.cron.prop:-} и не устанавливайте свойство для отключения - смотрите @Scheduled
  • Отключите bean/service с @Scheduled метода @Scheduled, например, с помощью @ConditionalOnProperty("my.scheduleproperty.active") и не устанавливая свойство (или устанавливая его в значение false)