systemd-таймеры вместо cron
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 они работают только пока пользователь залогинен — об этом легко забыть.