Cron-вирази: п'ять полів на прикладах
Cron-вираз - це п'ять розділених пробілами полів, що визначають, коли запускається завдання: хвилина, година, день місяця, місяць, день тижня. Читаючи зліва направо, 30 2 * * 1 означає на 30-й хвилині 2-ї години будь-якого дня будь-якого місяця, якщо цей день - понеділок.
П'ять полів
Кожен стандартний Unix-рядок cron починається з тих самих п'яти полів, за якими йде команда для запуску.
* * * * * command to run
| | | | |
| | | | +-- day of week (0-7, 0 and 7 both mean Sunday, or SUN-SAT)
| | | +---- month (1-12, or JAN-DEC)
| | +------ day of month (1-31)
| +-------- hour (0-23)
+---------- minute (0-59)
Поле містить одну з чотирьох речей: зірочку, що означає будь-яке значення, окреме число, список чи діапазон. Години подано у 24-годинному форматі без AM чи PM, тож 18:00 записують як 18. Неділю позначають і як 0, і як 7, бо різні системи історично розходились у цьому, і cron приймає обидва варіанти.
Деякі планувальники додають поля. Quartz, який використовують багато Java-фреймворків, ставить поле секунд першим і додає необов'язковий рік у кінці, тож вираз із шести чи семи полів, скопійований із довідника Quartz, не запрацює в Linux-crontab. Перед тим як копіювати вираз звідкись, перевірте, для якого саме різновиду cron ви його пишете.
Спеціальні символи
*відповідає будь-якому значенню в полі.* * * * *запускається щохвилини.,перелічує значення.0 8,13,20 * * *запускається о 08:00, 13:00 і 20:00.-задає діапазон.0 9-17 * * *запускається щогодини з 09:00 до 17:00./задає крок у діапазоні.*/15 * * * *запускається на 0-й, 15-й, 30-й і 45-й хвилинах. Його можна поєднати з діапазоном:0 9-17/2 * * *запускається о 9, 11, 13, 15 і 17.- Назви.
MON-SUNіJAN-DECпрацюють в останніх двох полях і читаються краще за числа. Їх не можна використовувати всередині кроку.
Ще чотири символи постійно трапляються в туторіалах і не існують у стандартному cron. L для останнього дня, W для найближчого буднього дня, # для n-го дня тижня місяця і ? замість зірочки - це розширення Quartz. Вираз на кшталт 0 0 L * * буде відхилено Linux-crontab. Щоб запускати щось в останній день місяця там, запускайте це щодня і дозвольте команді самій вирішити:
0 0 * * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/month-end.sh
Зверніть увагу на зворотні слеші в цьому рядку. Знак відсотка має особливе значення в crontab, і це п'ята помилка з переліку нижче.
Cron також приймає шість скорочених рядків замість усіх п'яти полів: @yearly (пишеться і як @annually), @monthly, @weekly, @daily (також @midnight), @hourly і @reboot, що запускається один раз при старті cron, а не за годинником. @reboot підтримується не всюди.
Поширені розклади
| Коли має запускатися | Вираз |
|---|---|
| Щохвилини | * * * * * |
| Кожні 5 хвилин | */5 * * * * |
| Кожні 30 хвилин | 0,30 * * * * |
| Щогодини, рівно | 0 * * * * |
| Кожні 2 години | 0 */2 * * * |
| Щодня опівночі | 0 0 * * * |
| Щодня о 02:30 | 30 2 * * * |
| Двічі на день, 08:00 і 20:00 | 0 8,20 * * * |
| По буднях о 09:00 | 0 9 * * MON-FRI |
| Щогодини в робочий час, по буднях | 0 9-17 * * MON-FRI |
| Щопонеділка о 07:00 | 0 7 * * MON |
| Щонеділі о 03:15 | 15 3 * * SUN |
| Першого числа місяця о 06:00 | 0 6 1 * * |
| Щокварталу, 1 січня, квітня, липня, жовтня | 0 0 1 1,4,7,10 * |
Помилки, що зсувають завдання не на той час
- Заповнення обох полів дня. Це та помилка, на якій ловляться всі. Коли день місяця й день тижня одночасно задано не зірочкою, cron запускає завдання, коли збігається будь-яке з них, а не обидва одразу.
0 0 13 * FRIзапускається кожного 13-го числа і кожної п'ятниці, а не лише в п'ятницю 13-го. - Крок, що не ділить діапазон.
*/7 * * * *спрацьовує на хвилинах 0, 7, 14, 21, 28, 35, 42, 49 і 56, а потім знову з 0. Розрив на межі години становить чотири хвилини, а не сім. Та сама пастка діє для*/40у полі хвилин і для будь-якого кроку, що не є дільником 60. - Крок не в тому полі.
*/2 * * * *- це кожні дві хвилини.0 */2 * * *- це кожні дві години. Пропущений початковий0перетворює погодинне завдання на завдання, що запускається в 30 разів частіше. - Припущення щодо середовища. Cron дає завданню мінімальне середовище, зазвичай трохи більше за
PATH=/usr/bin:/binіSHELL=/bin/sh. Скрипт, що працює у вашій оболонці, у cron падає, бо викликає щось із/usr/local/bin. Використовуйте абсолютні шляхи і в самій команді, і всередині неї. - Неекранований знак відсотка. У crontab
%перетворюється на перехід рядка, і все, що після першого такого символу, подається команді як стандартний ввід.date +%Y-%m-%dу рядку crontab потрібно писати якdate +\%Y-\%m-\%d. - Ігнорування виводу. Усе, що завдання виводить, надсилається поштою власнику crontab, а на машині без налаштованої пошти просто відкидається. Спрямуйте це туди, де ви це прочитаєте:
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1 - Дозвіл на перекриття запусків. Cron запускає наступний прогін за розкладом незалежно від того, чи завершився попередній. Обгорніть довгі завдання блокуванням:
*/5 * * * * flock -n /tmp/sync.lock /usr/local/bin/sync.sh - Забуті переведення годинника. Cron використовує локальний час машини. У дні переведення стрілок година близько 02:00 або не існує, або настає двічі, тож завдання, заплановане в цьому проміжку, може бути пропущене чи запущене двічі, залежно від реалізації cron. Виставте на серверах UTC або плануйте поза цим вікном.
- Набір
crontab -r. Ця команда видаляє весь crontab без жодного підтвердження, і вона на одну клавішу відcrontab -e. Тримайте crontab у системі контролю версій і встановлюйте його з файлу.
Перевірте ззовні
Вираз, що коректно парситься, - не те саме, що завдання, яке справді виконалося. Перевіряйте обидва варіанти: спершу на самій машині, потім ззовні неї.
На машині підтвердьте, що встановлено, що показує годинник і чи запустив cron завдання:
crontab -l
timedatectl
grep CRON /var/log/syslog | tail -20
journalctl -u cron -u crond --since "2 hours ago"
Рядок логу підтверджує, що cron запустив команду. Він нічого не каже про те, чи команда виконалася успішно, тому перенаправлення в лог-файл із помилок вище й важливе.
Потім перевірте результат так, як це зробив би користувач, - ззовні сервера. Більшість запланованих завдань існують, щоб змінити щось спостережуване: стрічку, у якій має бути сьогоднішня дата, карту сайту, яку мало бути переписано, експорт, який мав з'явитися. Запитайте про це й прочитайте заголовки:
curl -sI https://example.com/exports/daily.json
curl -s https://example.com/health/last-run
Заголовок Last-Modified підказує, чи файл свіжий, і робить це без доступу до оболонки. Запуск того самого запиту з кількох локацій через HTTP-перевірку відрізняє завдання, що не виконалося, від сторінки, закешованої на краї мережі в одному регіоні й застарілої лише там. Ця відмінність непомітна з одного curl на самому сервері.
Як дізнатися, що заплановане завдання перестало виконуватись
Cron-завдання, що перестало виконуватися, не дає нічого, що можна помітити. Немає ані сторінки помилки, ані невдалого запиту, тож нічого не викличе сповіщення, якщо за відсутністю нічого не стежить. Моніторити варто саме результат роботи завдання, а не саме завдання: файл стану, який воно переписує, мітку часу, яку публікує, ендпоінт, що повідомляє про останній успішний запуск. Запланована перевірка цього ендпоінту перетворює тиху відмову на сповіщення, і HostTracker надсилає такі сповіщення електронною поштою, SMS, голосовим дзвінком, у Slack, Telegram та іншими способами через 13 типів моніторів. Механіку налаштування описано в посібнику з HTTP-перевірки, решта посібників з усунення несправностей зібрана в розділі виправлень, а повний список типів перевірок на сторінці можливостей.