Cron-выражения: как читать расписание crontab
Пять полей cron, шаги и диапазоны, ловушка «день месяца / день недели» и набор готовых расписаний, которые можно скопировать в свой crontab.
Я потерял на неверно прочитанной строке 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-выражений, прочитайте фразу, которую он выдаёт, и взгляните на ближайшие пять запусков. Если фраза совпадает с тем, что вы имели в виду, — отправляйте в работу.