Таймеры systemd вместо cron: что удобнее на практике
Cron никуда не делся и работает, но на серверах с systemd я всё чаще переношу задачи на таймеры. Причина простая: логи, зависимости и повторный запуск уже есть из коробки.
Минимальный пример
Задача — раз в сутки обновлять список пакетов и складывать в файл.
[Unit] Description=Daily apt update cache After=network-online.target Wants=network-online.target [Service] Type=oneshot ExecStart=/usr/bin/apt-get update Nice=10 IOSchedulingClass=idle
Файл: /etc/systemd/system/apt-update.service.
[Unit] Description=Run apt-update daily [Timer] OnCalendar=*-*-* 04:20:00 RandomizedDelaySec=15m Persistent=true [Install] WantedBy=timers.target
Файл: /etc/systemd/system/apt-update.timer. Затем:
systemctl daemon-reload systemctl enable --now apt-update.timer systemctl list-timers apt-update.timer
Что мне нравится
-
Логи.
journalctl -u apt-updateсразу показывает и stdout, и код возврата. С cron приходится помнить проMAILTOи редиректы. -
Persistent=true— если сервер был выключен в момент запуска, задача выполнится при следующей загрузке. У cron аналога нет, нуженanacron. -
RandomizedDelaySec— размывает нагрузку, когда десяток серверов запускают одно и то же в одну секунду.
Что неудобно
Порог входа выше: вместо одной строки в crontab — два файла. Для
одноразовой задачи «запустить через 10 минут» cron или
systemd-run --on-active=10m всё ещё быстрее.
И ещё: OnCalendar понимает далеко не все «человеческие»
форматы. Проверять синтаксис удобно так:
systemd-analyze calendar "*-*-* 04:20:00"
Перенос с cron без сюрпризов
Главная разница — окружение. Cron запускает задачу с почти пустым
PATH и без вашего профиля. В юните systemd PATH
тоже минимальный, поэтому либо указывайте абсолютные пути, либо задавайте
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin.
Проверка ровно та же, что и с cron: запустить руками через
systemctl start apt-update.service и посмотреть
journalctl -u apt-update -n 50.