line — заметки на полях

systemd-таймеры вместо cron

3 ноября 2025

Cron никуда не делся и прекрасно работает, но для новых задач я давно пишу таймеры. Три причины: вывод задачи попадает в журнал, пропущенный из-за выключенной машины запуск можно догнать, а запустить задачу руками можно ровно в том же окружении, что и по расписанию.

Две единицы вместо одной строки

Сама задача — обычный сервис типа oneshot, /etc/systemd/system/backup.service:

[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
Nice=10
IOSchedulingClass=idle

Расписание — /etc/systemd/system/backup.timer с тем же именем:

[Unit]
Description=Run backup every night

[Timer]
OnCalendar=*-*-* 03:30:00
RandomizedDelaySec=15m
Persistent=true

[Install]
WantedBy=timers.target

Включается именно таймер, не сервис:

systemctl daemon-reload
systemctl enable --now backup.timer

Что дают параметры

  • Persistent=true — если в 03:30 машина была выключена, задача выполнится сразу после загрузки. Для ноутбуков и домашних серверов это главное отличие от cron.
  • RandomizedDelaySec=15m — случайная задержка до 15 минут. Полезно, когда несколько машин ходят в одно хранилище и не должны делать это одновременно.
  • Nice и IOSchedulingClass=idle в сервисе — чтобы бэкап не мешал всему остальному.

Проверка расписания

Синтаксис OnCalendar непривычный, но его можно проверить заранее:

$ systemd-analyze calendar "Mon..Fri 09:00"
  Original form: Mon..Fri 09:00
Normalized form: Mon..Fri *-*-* 09:00:00
    Next elapse: Mon 2025-11-03 09:00:00 MSK

Все таймеры с временем следующего и предыдущего запуска:

systemctl list-timers

Ручной запуск и логи

Запустить задачу вне расписания — это просто запустить сервис:

systemctl start backup.service
journalctl -u backup.service -n 50

Никаких перенаправлений вывода в файл и писем от cron: всё, что скрипт пишет в stdout и stderr, лежит в журнале вместе с кодом возврата. Если задача упала, systemctl status backup.service покажет failed, и это видно в systemctl --failed.

Когда cron всё-таки проще

Для пользовательской задачи на машине, где нет root, crontab -e быстрее. Таймеры есть и в пользовательском режиме (systemctl --user), но без loginctl enable-linger они работают только пока пользователь залогинен — об этом легко забыть.