Короткий ответ
Timer и service — два unit. Зелёный backup.timer не значит, что backup.service отработал успешно. Смотрите systemctl list-timers --all, systemctl cat backup.timer backup.service, journalctl -u backup.service. Persistent=true догоняет пропущенные слоты после выключения; без него ночной reboot «съест» 03:00. OnCalendar= парсится в локали systemd, не в crontab-синтаксисе. Не чините timer правкой cron.
Хост host.example (10.0.20.10), пользователь admin.
Симптомы и как отличить
- в
list-timersколонка LAST пустая; - NEXT в прошлом (часы убежали) — NTP;
- timer triggering, service failed — сервис;
- ждали cron — cron.
| Поле timer | Смысл |
|---|---|
| OnBootSec | через N после boot |
| OnUnitActiveSec | период от прошлого успешного? старта unit — читайте man |
| OnCalendar | календарь |
| Persistent | догон после downtime |
| RandomizedDelaySec | размазать apt-daily |
Возможные причины
systemctl enableсделали только service, не timer.- Имена не парные:
backup.timerзапускает неbackup.service(Unit=). Persistent=false(дефолт) и машина была выключена.- Невалидный календарь, timer inactive.
ConditionPathExistsу service ложен.- Часовой пояс unit vs
timedatectl. OnCalendarс секундами vs AccuracySec=1min — сдвиг.
Диагностика
systemctl list-timers --all --no-pager
systemctl status backup.timer backup.service --no-pager -l
systemctl cat backup.timer
systemctl cat backup.service
systemctl show backup.timer -p TimersCalendar,Persistent,LastTriggerUSec,NextElapseUSecRealtime,UnitПроверка календаря:
systemd-analyze calendar 'Tue *-*-* 03:15:00'
systemd-analyze calendar '*-*-* 03:15:00' --iterations=5Журнал:
journalctl -u backup.timer -u backup.service --since '7 days ago' --no-pagerЕсли LAST есть, а файлов нет — смотрите exit code service, диск, права.
Ручной запуск service, не timer:
sudo systemctl start backup.service
echo $?
systemctl status backup.service --no-pagerЕсли вручную ок, а по календарю нет — проблема timer/времени, не скрипта.
Время машины:
timedatectl
systemctl show backup.timer -p TimezoneРешение
Сценарий A. Timer не enabled
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timerenable service не обязателен, если только timer его стартует (RemainAfterExit/Type oneshot типичен).
Сценарий B. Нужен догон после reboot
Drop-in:
[Timer]
Persistent=truesudo systemctl daemon-reload
sudo systemctl restart backup.timerПомните: после долгого downtime oneshot может стартовать сразу при boot — нагрузка на диск. Для тяжёлых job добавьте OnBootSec=10min вдобавок или RandomizedDelay.
Сценарий C. Календарь
[Timer]
OnCalendar=*-*-* 03:15:00
AccuracySec=1minНе копируйте 0 3 * * * внутрь OnCalendar — это не cron.
Сценарий D. Unit= указывает не туда
В [Timer] Unit=backup.service явно. Имя по умолчанию — префикс timer.
Сценарий E. oneshot падает из‑за ENOSPC
Чистите диск, иначе timer будет «срабатывать» в failed. Диск.
Связка timer, service и календарь: частые ошибки enable
systemctl enable backup.service без timer запускает service на boot, если есть WantedBy=multi-user.target, и не создаёт календарь. Наоборот, enable backup.timer достаточно для расписания. Проверьте systemctl list-unit-files 'backup.*'.
OnCalendar=daily это 00:00:00 локального времени systemd. Если timedatectl в UTC, «ночью» для Москвы это не то. Явно пишите *-*-* 03:15:00 и держите TZ хоста осознанно.
RandomizedDelaySec=12h у apt-daily может сдвинуть job на половину суток — это не «timer не работает». Смотрите systemctl list-timers apt-daily.timer колонку NEXT.
Для Type=oneshot без RemainAfterExit=yes unit сразу inactive после успеха. list-timers LAST всё равно обновится. Не ждите is-active backup.service == active как критерий успеха oneshot — смотрите journal и артефакт.
Проверка парсинга с итерациями на неделю:
systemd-analyze calendar 'Mon *-*-* 04:00:00' --iterations=8Если дата в прошлом относительно Persistent=true, при enable --now job может стартовать немедленно. На тяжёлом dump это сюрприз в рабочее время: сначала enable без --now, потом start в окне.
AccuracySec=1h у некоторых vendor timer (энергосбережение) сдвигает «03:15» куда угодно внутри часа. Для бэкапа с окном 03:00–03:30 поставьте AccuracySec=1min. Проверка: systemctl show backup.timer -p AccuracyUSec.
WakeSystem=true на сервере без RTC wake бесполезен и путает. Не копируйте desktop-unit.
Если service вызывает bash /opt/backup.sh без PATH= в unit, cron-привычка «на сервере же стоит mysql» ломается: в systemd PATH узкий. Дублируйте абсолютные пути как в статье cron, но уже в [Service] Environment=PATH=....
Конфликт имён: пакет установил /lib/systemd/system/backup.timer, вы положили /etc/systemd/system/backup.timer целиком. Полный файл в /etc заменяет vendor, drop-in — нет. systemctl cat покажет, что реально действует. После apt upgrade пакета ваш полный override может скрыть новые After= зависимости — предпочтительнее drop-in.
Логи Started backup.service без Finished при Type=oneshot значат, что скрипт не вышел. Timer не «пропустил», он ждёт или упёрся в TimeoutStartSec (по умолчанию 90 с для многих unit, для oneshot часто infinity — уточните systemctl show -p TimeoutStartUSec). Долгий dump должен иметь явный TimeoutStartSec=6h.
OnCalendar= несколько строк в одном timer — ИЛИ по событиям (сработает на любое совпадение). Не думайте, что это AND. Для «в 3:15 И только в вс» пишите Sun *-*-* 03:15:00.
systemctl reset-failed backup.service перед ручной проверкой, иначе StartLimit не пустит. После серии failed timer может перестать запускать service до reset.
Как проверить, что проблема устранена
Временный календарь через минуту (потом вернуть боевой):
[Timer]
OnCalendar=*-*-* *:0/1:00
Persistent=falseИли:
sudo systemctl start backup.timer
# форсировать:
sudo systemctl start backup.service
journalctl -u backup.service -n 20Проверьте артефакт job. list-timers LAST обновился.
С admin@10.0.20.10 после суток — LAST не старше ожидаемого интервала.
Если не помогло
Failed to parse calendar— systemd-analyze, локаль.- Timer в user.slice:
systemctl --user, lingerloginctl enable-linger admin. - Конфликт cron и timer на один скрипт — оставьте один оркестратор.
Профилактика
- Пара файлов
.timer+.serviceв/etc/systemd/system. - Мониторинг LAST и
systemctl is-failed backup.service. - Не полагаться на точность секунд без
AccuracySec=1us(и даже тогда NTP). - Документировать Persistent для бэкапов.
FAQ
Чем timer лучше cron?
Календарь, зависимости, cgroup, journal. Cron проще для одной строки. Не мигрируйте всё ради моды.
OnUnitActiveSec=1d от успешного или любого старта?
От активации unit. Если service failed быстро, период всё равно идёт. Читайте man systemd.timer.
Нужен ли WantedBy=timers.target?
Да для enable. Без Install секции enable не привяжет.
Почему apt-daily «случайно»?
RandomizedDelaySec. Не ставьте 0 глобально, получите thundering herd зеркала.
Timer срабатывает дважды
Два unit, или Persistent догон + календарь, или enable в /lib и копия в /etc.