Перевёл cron-задачи на systemd timers
На домашнем сервере накопилось штук пятнадцать задач в crontab: бэкапы, чистка, синхронизация. Проблема была не в самом cron, а в том, что я не видел, какая задача упала и когда. Логи уходили в почту, которую никто не читал. Перенёс всё на systemd timers и не жалею.
Что даёт timer по сравнению с cron
- вывод задачи сразу в журнале:
journalctl -u backup.service; - видно, когда задача запускалась последний раз и когда запустится следующий:
systemctl list-timers; Persistent=true: если машина была выключена, пропущенный запуск выполнится после загрузки;- ограничения ресурсов (
CPUQuota,IOWeight) без обёрток; RandomizedDelaySec, чтобы десять задач не стартовали в 03:00 одновременно.
Минимальный пример
Два файла. Сервис описывает, что запускать:
# /etc/systemd/system/cleanup.service
[Unit]
Description=Очистка временных файлов
[Service]
Type=oneshot
ExecStart=/usr/local/bin/cleanup.sh
Nice=10
IOSchedulingClass=idle
Таймер описывает, когда:
# /etc/systemd/system/cleanup.timer
[Unit]
Description=Ежедневная очистка
[Timer]
OnCalendar=*-*-* 04:15:00
RandomizedDelaySec=15m
Persistent=true
[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now cleanup.timer
systemctl list-timers cleanup.timer
Проверить расписание до того, как ждать сутки
systemd-analyze calendar показывает, когда сработает выражение:
$ systemd-analyze calendar "Mon..Fri *-*-* 09:00"
Original form: Mon..Fri *-*-* 09:00
Normalized form: Mon..Fri *-*-* 09:00:00
Next elapse: ...
Уведомление о падении
Самое полезное: OnFailure=. Я завёл шаблонный сервис, который шлёт сообщение в Telegram-бота,
и подключил его ко всем задачам одной строкой:
[Unit]
OnFailure=notify-failure@%n.service
Теперь упавший бэкап я вижу в течение минуты, а не через месяц.
Где cron всё ещё удобнее
Для разовой задачи «запустить вот это каждые пять минут» два файла выглядят избыточно.
Тогда выручает systemd-run --on-calendar='*:0/5' /path/script.sh: он создаёт временный таймер без файлов.