Долго не видел смысла уходить с cron: он работает, синтаксис знаком, файл один. Смысл появился в тот момент, когда понадобилось узнать, почему ночная задача не отработала, — и выяснилось, что узнать это неоткуда.
Задача становится обычным юнитом. У неё есть статус, есть журнал, есть код возврата, её можно запустить руками той же командой, которой её запускает расписание. В cron всё это заменяется письмом на несуществующий почтовый ящик или строкой в общем логе.
Второе — расписание отделено от задачи. Один и тот же .service
можно дёргать и по таймеру, и вручную, и из другого юнита, не дублируя команду
в трёх местах.
| Директива | Что делает |
|---|---|
OnBootSec | Отсчёт от загрузки системы. Нужен, чтобы не бить в сеть в первую же секунду после старта, пока интерфейсы ещё поднимаются. |
OnUnitActiveSec | Отсчёт от прошлого запуска. Именно это даёт «раз в сутки», а не «в 3:00». |
Persistent | Если момент запуска был пропущен, потому что машина была выключена, задача выполнится сразу после включения. |
RandomizedDelaySec | Случайная задержка. Обязательна, если задача ходит на чужой сервер: иначе все машины с этим конфигом придут туда одновременно. |
Про Persistent стоит сказать отдельно. Это ровно та разница,
из-за которой на ноутбуке или на машине, которую иногда перезагружают,
cron-задача просто не выполняется и никто об этом не узнаёт.
[Unit] Description=Daily configuration refresh [Timer] OnBootSec=10m OnUnitActiveSec=1d RandomizedDelaySec=1h Persistent=true [Install] WantedBy=timers.target
Парный .service — обычный oneshot:
[Unit] Description=Refresh configuration [Service] Type=oneshot ExecStart=/usr/local/sbin/refresh-config ProtectSystem=strict ReadWritePaths=/etc/myapp
Включать нужно таймер, а не сервис:
systemctl enable --now refresh-config.timer
Ошибка на этом месте стоила мне вечера. Сервис при этом показывает
inactive (dead), что выглядит как поломка, хотя это нормальное
состояние oneshot-задачи между запусками.
Посмотреть расписание целиком:
systemctl list-timers --no-pager
Колонки NEXT и LAST отвечают на главный вопрос
эксплуатации — когда задача отработает и отработала ли вообще, — на который
cron не отвечает никак.