Что такое cron-выражение?
Cron-выражение — компактная строка расписания, указывающая планировщику задач, когда именно нужно запустить задачу. Формат появился в 1975 году в Unix V7 в демоне cron и с тех пор почти не изменился — та же пятипольная грамматика встречается сегодня в Kubernetes CronJobs, AWS EventBridge, рабочих процессах GitHub Actions, Google Cloud Scheduler, GitLab CI, пайплайнах Jenkins и бинарнике crontab, поставляемом с каждым дистрибутивом Linux. Грамматика вмещает много смысла в тринадцать символов — именно поэтому парсер, переводящий её в понятный текст, — это разница между уверенным деплоем и откатом в 3 часа ночи.
Как работает cron-выражение?
Стандартное cron-выражение состоит из пяти полей, разделённых пробелами, которые вместе определяют повторяющееся расписание. Каждую минуту движок сравнивает системное время с выражением и запускает задачу при совпадении всех пяти полей. Поля слева направо:
- Минута (0–59). В какую минуту часа выполняется задача.
0— начало часа,30— полчаса,*/5— каждые пять минут (00, 05, 10, ...), а15,45— в 15 и 45 минут. - Час (0–23). Час суток по 24-часовому формату.
0— полночь,9— 9 утра,17— 17 часов. Диапазоны (9-17для рабочего времени) и шаги (*/2для каждого второго часа) работают так же, как и для минут. - День месяца (1–31). В какой календарный день запускать.
1— первое число,*— каждый день,1,15— первое и пятнадцатое. Будьте осторожны с31— оно молча пропускает месяцы без 31-го дня. - Месяц (1–12 или JAN–DEC). В какие месяцы запускать.
*— каждый месяц,1,7— январь и июль,1-3— только первый квартал. Трёхбуквенные названия месяцев регистронезависимы в большинстве реализаций. - День недели (0–7, где 0 и 7 — воскресенье). Ограничивает запуск определёнными днями недели.
1-5— с понедельника по пятницу,0,6— выходные,MON-FRIработает в большинстве парсеров. Когда и день месяца, и день недели заданы конкретными значениями, классический cron запускается при совпадении любого из них (логическое ИЛИ) — это удивляет людей каждый раз.
Зачем использовать парсер cron-выражений?
- Поймайте молчаливую ошибку до деплоя. Выражение `0 2 */3 * *` запускается в 2:00 каждый третий день, а не каждые три минуты — вставьте его сюда, и вы увидите это на понятном языке до выхода в прод.
- Большинство облачных планировщиков по умолчанию работают в UTC. Предварительный просмотр следующих десяти запусков в вашем местном часовом поясе позволит выявить сдвиг из-за перехода на летнее время до того, как это разбудит кого-то в 3 ночи.
- Псевдонимы `@daily`, `@weekly` и `@monthly` удобны, но неоднозначны. Парсер показывает соответствующую пятипольную форму, чтобы вы точно знали, что было запланировано.
- Построитель поле за полем позволяет составлять расписание по одному столбцу и наблюдать, как обновляется описание в реальном времени — это намного быстрее, чем в десятый раз перечитывать man-страницу cron.
Где используются cron-выражения?
Синтаксис cron встречается везде, где задача должна повторяться по расписанию. Три наиболее распространённых сценария с характерными особенностями каждого:
- Расписания резервного копирования. Классическая запись `crontab -e` для сброса базы данных в S3 в 2:00 ночи или ротации архива `pg_dump` 1-го числа каждого месяца. Строка вида `0 2 * * * /usr/local/bin/backup.sh` была размещена на большем количестве серверов Linux, чем любая другая строка cron в истории. Правильно задайте минуту и час, перенаправьте stderr куда-нибудь надёжное — и вы заменили ручной чеклист автоматическим скриптом.
- Триггеры `schedule` в GitHub Actions. Ключ `on.schedule.cron` в `.github/workflows/*.yml` принимает стандартный пятипольный cron, но задание всегда выполняется в UTC, и GitHub молча пропускает запуск, если очередь раннеров занята. Распространённый паттерн: `cron: '0 9 * * 1-5'` для отправки дайджеста с понедельника по пятницу в 9:00 UTC. Проверьте его здесь в своём местном часовом поясе, чтобы обещанный дайджест в 9:00 не оказался в 10:00 по московскому времени.
- AWS EventBridge Scheduler. Cron-выражения EventBridge содержат шестое поле для года и требуют `?` вместо `*` в поле дня месяца или дня недели — `cron(0 9 ? * MON-FRI *)` является аналогом классического cron для 9:00 по будням. Используется для запуска Lambda по расписанию, ECS-задач и Step Function; несоответствие с классическим синтаксисом cron — главный источник ошибок `ValidationException` в деплоях CloudFormation.
Как выглядит настоящее cron-выражение?
Возьмём 0 9 * * 1-5 — запускается в 9:00 каждый будний день. Читая поля слева направо: 0 — нулевая минута часа, 9 — 9 часов утра по 24-часовому формату, * в поле дня месяца означает каждый день, * в поле месяца — каждый месяц, а 1-5 в поле дня недели ограничивает запуск понедельником–пятницей (где 1 = понедельник в стандартной нумерации cron). Вставьте это в поле ввода выше, и парсер подтвердит В 09:00, с понедельника по пятницу, отобразив следующие десять дат в выбранной IANA-зоне. Тот же смысл в синтаксисе AWS EventBridge: cron(0 9 ? * MON-FRI *) — обратите внимание на поле года в конце и `?` там, где в стандартном cron стоит `*`. То же в выражении Quartz (шесть полей с ведущими секундами): 0 0 9 ? * MON-FRI. Три разные платформы, три разные формы записи — одно расписание.
Cron-выражения непрощающие ровно в одном: опечатка даёт синтаксически корректное расписание, которое срабатывает в неподходящее время — без единой ошибки при код-ревью. Прочитать `0 0 1 * *` и сразу понять, что это полночь 1-го числа каждого месяца, а не 1 января, — дело навыка. Парсер выше превращает этот навык в десятисекундную проверку: вставьте выражение, прочитайте текст, просмотрите следующие десять запусков в своём часовом поясе и отправляйте YAML с уверенностью, что строка cron делает именно то, что написано в сообщении коммита.
В чём разница между пятипольным и шестипольным cron?
Пятипольный cron — классическая Unix-грамматика с разрешением в одну минуту. Шестипольный cron добавляет ведущий столбец секунд для суб-минутного планирования — применяется в Quartz и @Scheduled в Spring. AWS EventBridge тоже использует шесть полей, но его дополнительный столбец — завершающий год, а не секунды.
Что означают @hourly, @daily и @weekly?
Псевдонимы Vixie-cron, появившиеся в 1987 году. @hourly = 0 * * * *, @daily = 0 0 * * *, @weekly = 0 0 * * 0, @monthly = 0 0 1 * *, @yearly = 0 0 1 1 *. @reboot выполняется один раз при загрузке. GitHub Actions и EventBridge не поддерживают эти псевдонимы.
Воскресенье — день 0 или 7 в cron?
Оба значения принимаются в классическом Vixie cron — 0 и 7 обозначают воскресенье, чтобы диапазоны вроде 5-7 читались естественно как пятница–воскресенье. Понедельник — всегда 1, суббота — всегда 6. В Quartz и AWS EventBridge используется другое соглашение: 1-7, где воскресенье — 1. Проверяйте документацию платформы, прежде чем делать предположения.
Как cron обрабатывает переход на летнее время?
Зависит от часового пояса движка. В UTC (по умолчанию в EventBridge, Kubernetes и GitHub Actions) перехода на летнее время нет. В местном часовом поясе с DST классический Vixie cron пропускает задания во время «весеннего перехода» и запускает их дважды при «осеннем переходе»; таймеры systemd срабатывают ровно один раз.