Кварц: выражение Cron, которое никогда не будет выполнено
Я знаю, что здесь есть дубликат , который, вероятно, является именно моим делом, хотя он заслуживает лучшего объяснения, которое я попытаюсь предоставить здесь.
Я работаю с веб-приложением Java с использованием контекста приложения Spring. В этом контексте я определил запланированные задания с использованием Quartz. Эти задания запускаются cron, определенными в файле .properties.
Контекст Spring встроен в войну, а файл .properties находится на сервере приложений (Tomcat в данном конкретном случае).
Это просто прекрасно и позволяет определять разные кроссы в соответствии с окружающей средой (разработка, интеграция, производство,...).
Теперь, когда я запускаю это приложение локально на своем собственном компьютере, я не хочу, чтобы эти задания выполнялись. Есть ли способ написать выражение cron, которое никогда не будет срабатывать?
Ответы
Ответ 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
В следующий раз это будет выполнено:
- Понедельник, 29 февраля 2044 г., 3:00
- Понедельник, 29 февраля 2072 г., 3:00
- Понедельник, 29 февраля 2112 3:00
- Понедельник, 29 февраля 2140 3:00
- Понедельник, 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
)