belun.app Блог
EN

Cron-выражения: как читать расписание crontab

Пять полей cron, шаги и диапазоны, ловушка «день месяца / день недели» и набор готовых расписаний, которые можно скопировать в свой crontab.

Серверная с часами и табло расписания — cron-выражения для автоматических задач

Я потерял на неверно прочитанной строке cron больше времени, чем хотелось бы признавать. Классика жанра: резервная копия, которая должна была делаться раз в сутки, запускалась каждую минуту — потому что * оказалась не в том поле. Пять маленьких полей, и одно из них не на месте тихо съедает вечер. Генератор cron-выражений нужен ровно для того, чтобы проверить расписание заранее, а не постфактум.

Пять полей слева направо

Строка cron — это пять значений через пробел:

* * * * *
│ │ │ │ │
│ │ │ │ └── день недели (0–6, воскресенье — 0)
│ │ │ └──── месяц (1–12)
│ │ └────── день месяца (1–31)
│ └──────── час (0–23)
└────────── минута (0–59)

* значит «каждый». Тогда 30 8 * * 1 читается так: минута 30, час 8, любой день, любой месяц, понедельник. То есть 8:30 каждый понедельник. Читайте слева направо — и шифр перестаёт быть шифром.

Шаги, диапазоны и списки

Три кусочка синтаксиса покрывают почти всё, что вам понадобится:

  • Диапазон задаётся через дефис: 1-5 в поле дня недели — это с понедельника по пятницу.
  • Список — через запятые: 0,30 в поле минут означает в начале часа и в половину.
  • Шаг — через слэш: */15 означает каждое 15-е значение: минуты 0, 15, 30, 45.

Их можно сочетать. 0-30/10 в минутах даёт 0, 10, 20, 30. А 0 9-17 * * 1-5 — это «в начале часа, с 9 до 17, по будням», нормальное расписание для задачи, которая должна работать только в рабочие часы.

Ловушка, на которую попадаются все

Вот по-настоящему запутанный момент, и вашей вины тут нет. Когда оба поля — день месяца и день недели — заданы не как *, cron трактует их как ИЛИ, а не И.

Возьмём 0 0 13 * 5. Можно прочитать это как «полночь в пятницу 13-го». На самом деле задача сработает в полночь 13-го числа каждого месяца и каждую пятницу. Два отдельных триггера, объединённых вместе. Это поведение тянется ещё от оригинального Vixie cron и описано в man-странице, но man-страницу почти никто не открывает, пока что-нибудь уже не сломалось. Генератор следует этому правилу при расчёте запусков, так что вы увидите реальное расписание, а не то, что себе представили.

Расписания, которые стоит запомнить

Несколько встречаются постоянно:

  • */5 * * * * — каждые 5 минут, рабочая лошадка для проверок доступности
  • 0 * * * * — раз в час, в начале часа
  • 0 3 * * * — в 3 ночи ежедневно, тихое окно для бэкапов
  • 0 0 * * 0 — полночь каждое воскресенье
  • 0 0 1 * * — полночь 1-го числа каждого месяца

Большинство систем понимают и короткие макросы. @daily, @hourly, @weekly и компания разворачиваются в эквивалентную строку из пяти полей, а @reboot срабатывает один раз при старте машины. Их легче читать с первого взгляда, хотя обычные поля дают более тонкий контроль.

Пара слов про часовые пояса

Cron работает по системным часам той машины, где он живёт. Сервер в UTC и ваш ноутбук в Берлине разойдутся во мнениях о том, когда наступит 0 9 * * *. Генератор показывает ближайшие запуски в локальном времени браузера — это удобно, чтобы проверить сам шаблон, но не забудьте пересчитать его на часовой пояс сервера, прежде чем доверять расписанию в продакшене.

Вставьте свою строку в Генератор cron-выражений, прочитайте фразу, которую он выдаёт, и взгляните на ближайшие пять запусков. Если фраза совпадает с тем, что вы имели в виду, — отправляйте в работу.

Попробуйте инструмент

Генератор cron-выражений →