У меня есть ThreadPoolTaskScheduler, запланированный CronTrigger, и я наблюдаю довольно странную вещь. Я запускаю в нем простую задачу, которая просто печатает текущую дату и время. Как это:
public class MyCron {
Logger logger = LoggerFactory.getLogger(MyCron);
private final ThreadPoolTaskScheduler scheduler;
private final CronTrigger cronTrigger;
private ScheduledFuture<?> runnableTask;
public MyCron(String cronEntry) {
this.scheduler = new ThreadPoolTaskScheduler();
this.scheduler.setPoolSize(10);
this.scheduler.setThreadNamePrefix("MyCron-" + name + "-");
this.scheduler.initialize();
this.cronTrigger = new CronTrigger(cronEntry);
runnableTask = scheduler.schedule(this::workerThread, cronTrigger);
}
где this::workerThread печатает дату и время. Но я заметил, что он запускается немного раньше запланированного, например, для строк cron 0 */5 * * * * и 0 */7 * * * * я наблюдаю следующее:
mycron | 2024-05-30T17:59:59.844Z INFO 1 --- [n-Cron test 2-7] c.e : Cron test 2 worker is running: Thu May 30 2024 17:59:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:04:59.785Z INFO 1 --- [n-Cron test 1-1] c.e : Cron test 1 worker is running: Thu May 30 2024 18:04:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:06:59.702Z INFO 1 --- [n-Cron test 2-7] c.e : Cron test 2 worker is running: Thu May 30 2024 18:06:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:09:59.785Z INFO 1 --- [n-Cron test 1-1] c.e : Cron test 1 worker is running: Thu May 30 2024 18:09:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:13:59.702Z INFO 1 --- [n-Cron test 2-7] c.e : Cron test 2 worker is running: Thu May 30 2024 18:13:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:14:59.784Z INFO 1 --- [n-Cron test 1-1] c.e : Cron test 1 worker is running: Thu May 30 2024 18:14:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:19:59.785Z INFO 1 --- [n-Cron test 1-1] c.e : Cron test 1 worker is running: Thu May 30 2024 18:19:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:20:59.665Z INFO 1 --- [n-Cron test 2-7] c.e : Cron test 2 worker is running: Thu May 30 2024 18:20:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:24:59.746Z INFO 1 --- [n-Cron test 1-1] c.e : Cron test 1 worker is running: Thu May 30 2024 18:24:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:27:59.692Z INFO 1 --- [n-Cron test 2-7] c.e : Cron test 2 worker is running: Thu May 30 2024 18:27:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:29:59.783Z INFO 1 --- [n-Cron test 1-1] c.e : Cron test 1 worker is running: Thu May 30 2024 18:29:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:34:59.694Z INFO 1 --- [n-Cron test 2-7] c.e : Cron test 2 worker is running: Thu May 30 2024 18:34:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:34:59.783Z INFO 1 --- [n-Cron test 1-1] c.e : Cron test 1 worker is running: Thu May 30 2024 18:34:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:39:59.782Z INFO 1 --- [n-Cron test 1-1] c.e : Cron test 1 worker is running: Thu May 30 2024 18:39:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:41:59.694Z INFO 1 --- [n-Cron test 2-7] c.e : Cron test 2 worker is running: Thu May 30 2024 18:41:59 GMT+0000 (UTC)
mycron | 2024-05-30T18:44:59.790Z INFO 1 --- [n-Cron test 1-1] c.e : Cron test 1 worker is running: Thu May 30 2024 18:44:59 GMT+0000 (UTC)
Я не понимаю, как это возможно и почему такое могло произойти. Я делаю что-то неправильно?
Мои версии: Running with Spring Boot v3.3.0, Spring v6.1.8
Спасибо!
Обновление: я вижу закрытый запрос, потому что вопрос неясен. Я предполагал, что это довольно ясно, но я все равно попытаюсь объяснить это дальше. Поскольку я указал, что секунды CronTrigger установлены на ноль, я ожидаю, что мой планировщик будет работать через ноль секунд, а не на 59-й секунде. Это минимум. Другая сторона заключается в том, что если я настрою запуск каждые 5 минут, я ожидаю, что он запустится в 18:05:00, а не в 18:04:59. Вот ссылка на javadoc: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/support/CronExpression.html#parse(java.lang.String)
Обновление/объяснение – почему это важно:
В моем task я запускаю sql-запрос с условием where, например where timestamp < current_timestamp() Поскольку он выполняется внутри контейнера, он выполняется очень быстро, и условие не срабатывает. Странно, неужели это такой редкий случай?
Почему? В основном потому, что я указал, чтобы он запускался каждые 5 и 7 минут.
Ваши выражения cron недействительны: «0 */7 * * * *». Выражение Cron не поддерживает день недели и день месяца одновременно. Вот допустимое выражение cron каждые 7 минут: «0 0/7 0 ? * * *»
@AnotherOne это не cron, как я уже писал, это CronTrigger docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
0 */5 * * * * ==> каждые 5 минут. Попробуйте 0 0/5 * * * *
@Khanna111Khanna111 Извините, не понял вашей мысли. Не могли бы вы уточнить, пожалуйста?
@Khanna111 Типа, я имею в виду - сначала "0" означает "каждую 0-ю секунду". И что я наблюдаю - секунды, как вы могли видеть в журнале, равны 59




Реализация
CronExpression
округляет до секунды. Поэтому он не может гарантировать выполнение именно в эту секунду (каждую 0-ю секунду).
Из журналов видно, что значение milli second округляется до ближайшей секунды. Таким образом, хотя в качестве второго значения отображается 59, мс округляются в большую сторону и «каждая 0-я секунда» является истиной.
Не могли бы вы поделиться источником этой информации?
Ну, судя по выпуску 29735, они считают, что это не баг. Итак, я добавил такой код в task в качестве обходного пути.
long now = System.currentTimeMillis();
long fraction = now - now / 1000 * 1000;
if (fraction > 500) {
TimeUnit.MILLISECONDS.sleep(1000L - fraction);
}
Немного слишком некрасиво и вонюче, но других решений я не вижу, так как исправлять это не хотят.
Как вы думаете, почему он запускается раньше?