# systemd timers - замена cron _Процессы и ресурсы · LinuxLab Knowledge Base_ **TL;DR:** systemd timer - unit-файл `.timer`, запускающий парный `.service` по расписанию или через интервал после события (boot, last-run). Замена cron с логами в [[cmd-journalctl]] и зависимостями. ## Зачем не cron cron умеет одно: «дёргай скрипт в эту минуту». systemd timer умеет: - Запускать через **интервал после события** (5 минут после boot, 1 час после предыдущего запуска), а не только в фиксированный момент времени. - Догонять пропущенные срабатывания после выключения хоста (`Persistent=true`). - Писать stdout/stderr **автоматически** в [cmd-journalctl](/kb/cmd-journalctl.md) - никаких `>> /var/log/myapp.log 2>&1` в скрипте. - Использовать всю инфраструктуру [systemd](/kb/systemd.md): зависимости (`After=`/`Requires=`), sandbox-изоляцию (`PrivateTmp=`, `ProtectSystem=`), cgroup-лимиты (`MemoryMax=`). - Рандомизировать старт (`RandomizedDelaySec=`) чтобы 200 хостов не били в backup-сервер одновременно. Cron остался - он не deprecated. Но для нового кода systemd timer удобнее. ## Парность .timer + .service Timer всегда работает в паре с одноимённым (или явно указанным) service-юнитом: ``` /etc/systemd/system/backup.timer ← когда запускать /etc/systemd/system/backup.service ← что запускать ``` По умолчанию `backup.timer` триггерит `backup.service`. Если имена различаются - указать явно: ```ini [Timer] Unit=other-backup.service ``` ## Типы триггеров | Директива | Тип | Когда срабатывает | |-----------------------|-----------|--------------------------------------------------| | `OnCalendar=` | calendar | В указанное время по календарю (как cron) | | `OnBootSec=` | monotonic | Через N после загрузки ядра | | `OnStartupSec=` | monotonic | Через N после старта systemd (≈ то же что boot) | | `OnActiveSec=` | monotonic | Через N после активации самого таймера | | `OnUnitActiveSec=` | monotonic | Через N после прошлого старта парного service | | `OnUnitInactiveSec=` | monotonic | Через N после прошлого завершения парного service| **Monotonic** = считается от события, не от стенки. Не персистентный по умолчанию (после reboot счётчик сбрасывается). Удобно для «запусти через 10 минут после boot, потом каждые 6 часов». Можно комбинировать - несколько `On*` в одном [Timer], сработает на любом условии. ## OnCalendar - синтаксис Формат: `DOW YYYY-MM-DD HH:MM:SS`. DOW и любые поля можно опускать (`*`). | Выражение | Что значит | |-----------------------------|--------------------------------------------------| | `*-*-* 03:00:00` | каждый день в 03:00 | | `Mon..Fri *-*-* 09:00` | по будням в 09:00 | | `Mon *-*-* 00:00:00` | каждый понедельник полночь (= `weekly`) | | `*-*-01 00:00:00` | первого числа каждого месяца (= `monthly`) | | `*-*-* *:0/15:00` | каждые 15 минут | | `2026-6,7,8-1,15 01:15:00` | 1 и 15 июня, июля, августа 2026 | | `Mon *-05~03` | первый понедельник = третий с конца мая | | `*-05~03/2` | третий с конца мая, потом через каждые 2 дня | Алиасы: `minutely`, `hourly`, `daily`, `weekly`, `monthly`, `yearly`. Проверить выражение перед коммитом - обязательно: ```bash systemd-analyze calendar "Mon..Fri *-*-* 09:00" # Original form: Mon..Fri *-*-* 09:00 # Normalized form: Mon..Fri *-*-* 09:00:00 # Next elapse: Wed 2026-04-30 09:00:00 EDT # From now: 14h left ``` ## AccuracySec и RandomizedDelaySec - почему не точно По умолчанию systemd триггерит таймер не точно в указанную секунду, а в **окно длиной 1 минута** начиная с указанного времени. Это **сделано специально**: если 5 таймеров стоят на `daily` (= 00:00:00), они стартанут одновременно и положат I/O. ```ini [Timer] OnCalendar=daily AccuracySec=1us # узкое окно - триггер в указанную секунду RandomizedDelaySec=30min # ещё и случайная задержка до 30 мин ``` Дефолт большинства системных таймеров - `AccuracySec=1h` или больше. Сужать только если задача реально критична ко времени. ## Persistent - догонять после downtime По умолчанию если в момент срабатывания хост был выключен - событие пропущено. С `Persistent=true` (только для `OnCalendar=`) systemd запоминает время последнего запуска в `/var/lib/systemd/timers/` и при старте проверяет - если пропустили, дёргает прямо сейчас. ```ini [Timer] OnCalendar=daily Persistent=true # критично для backup'ов на ноутбуках/dev-VM ``` ## Минимальный пример: backup каждые 6 часов `/etc/systemd/system/backup.service`: ```ini [Unit] Description=Nightly backup After=network-online.target [Service] Type=oneshot ExecStart=/usr/local/bin/do-backup.sh User=backup ``` `/etc/systemd/system/backup.timer`: ```ini [Unit] Description=Backup every 6h after boot [Timer] OnBootSec=15min OnUnitActiveSec=6h Persistent=true RandomizedDelaySec=5min [Install] WantedBy=timers.target ``` Активировать: ```bash sudo systemctl daemon-reload sudo systemctl enable --now backup.timer systemctl list-timers backup.timer ``` Обрати внимание: `WantedBy=timers.target` (не `multi-user.target`), иначе таймер не подхватится при загрузке. ## Просмотр и дебаг ```bash systemctl list-timers --all # все таймеры с next/last run systemctl status backup.timer # state одного таймера systemctl cat backup.timer # итоговый unit с drop-in'ами journalctl -u backup.service -S today # что писал триггерящийся service systemd-analyze calendar 'Mon *-*-* 04:00' # проверка OnCalendar systemd-analyze timespan '15days 6h' # парсинг time-span ``` Удалить лишний дефолтный таймер (нет SSD - не нужен `fstrim`): ```bash sudo systemctl disable --now fstrim.timer ``` ## Команды ```bash systemctl list-timers --all ``` Все таймеры с next/last run и парным service - обзор расписания хоста ```bash systemd-analyze calendar 'Mon..Fri *-*-* 09:00' ``` Проверить корректность OnCalendar-выражения и увидеть когда сработает ```bash journalctl -u backup.service -S today ``` Логи последних запусков triggered-сервиса за сегодня ```bash systemctl cat backup.timer ``` Итоговый unit с применёнными drop-in'ами - то что реально читает systemd ```bash sudo systemctl enable --now backup.timer ``` Активировать таймер сейчас и при загрузке (не сам service - таймер!) ## См. также - [systemd - init и менеджер сервисов](/kb/systemd.md) - [systemctl - управление сервисами systemd](/kb/cmd-systemctl.md) - [journalctl - журнал systemd](/kb/cmd-journalctl.md) - [cron и crontab - расписание задач](/kb/cmd-cron-crontab.md) - [Типы systemd-юнитов](/kb/systemd-unit-types.md)