Systemd timers вместо cron: современное планирование задач

Преимущества systemd timers перед cron

Cron работает надёжно уже десятилетия, но systemd timers предлагают значительно больше возможностей для современных задач администрирования:

  • Централизованное логирование — вывод задач идёт в journald, доступен через journalctl
  • Управление зависимостями — таймер может зависеть от сети, монтирования и других сервисов
  • Контроль ресурсов — через cgroups: лимиты CPU, RAM, I/O
  • Точность до микросекунд — вместо минутной гранулярности cron
  • Гарантия выполненияPersistent=true запускает пропущенные задания после перезагрузки
  • РандомизацияRandomizedDelaySec предотвращает thundering herd
  • Мониторинг — статус через systemctl, интеграция с мониторингом

Cron до сих пор проще для тривиальных задач (одна строка), но для сложных сценариев с зависимостями, лимитами и мониторингом systemd timers — лучший выбор.

Структура таймера: unit-файлы

Systemd timer состоит из двух юнитов: .timer (расписание) и .service (действие). Оба файла размещаются в /etc/systemd/system/.

Пример: ежедневная очистка временных файлов.

Файл /etc/systemd/system/cleanup.service:

[Unit]
Description=Очистка временных файлов старше 7 дней
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/bin/find /tmp -type f -mtime +7 -delete
ExecStart=/usr/bin/find /var/tmp -type f -mtime +30 -delete

# Ограничение ресурсов
CPUQuota=25%
MemoryMax=256M
IOWeight=50

# Безопасность
ProtectSystem=full
PrivateTmp=true
NoNewPrivileges=true

Файл /etc/systemd/system/cleanup.timer:

[Unit]
Description=Запуск очистки ежедневно в 03:00

[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=1800
Persistent=true

[Install]
WantedBy=timers.target

Активация:

sudo systemctl daemon-reload
sudo systemctl enable --now cleanup.timer

Ключевые параметры секции [Timer]

Основные параметры расписания:

ПараметрОписаниеПример
OnCalendarКалендарное расписаниеMon *-*-* 09:00:00
OnBootSecПосле загрузки системы5min
OnUnitActiveSecПосле последнего запуска1h
PersistentЗапускать пропущенныеtrue
RandomizedDelaySecСлучайная задержка600
AccuracySecТочность (по умолчанию 1min)1s

Синтаксис OnCalendar

Формат OnCalendar гибче, чем crontab. Базовый формат: DayOfWeek Year-Month-Day Hour:Minute:Second.

Примеры расписаний:

# Каждые 15 минут
OnCalendar=*:0/15

# Каждый час
OnCalendar=hourly

# Каждый день в полночь
OnCalendar=daily

# Понедельник-пятница в 9:00
OnCalendar=Mon..Fri *-*-* 09:00:00

# Первое число каждого месяца в 06:00
OnCalendar=*-*-01 06:00:00

# Каждые 2 часа
OnCalendar=0/2:00:00

# Последний день месяца (через cron это невозможно)
OnCalendar=*-*~1 23:00:00

# Несколько расписаний
OnCalendar=Mon *-*-* 08:00:00
OnCalendar=Fri *-*-* 18:00:00

Проверьте расписание до активации:

systemd-analyze calendar "Mon..Fri *-*-* 09:00:00" --iterations=5

Команда покажет ближайшие 5 срабатываний — убедитесь, что расписание соответствует ожиданиям.

Монотонные таймеры

Монотонные таймеры срабатывают относительно события (загрузка, последний запуск), а не по расписанию. Идеальны для задач с интервалом:

[Unit]
Description=Проверка обновлений каждые 6 часов

[Timer]
# Через 10 минут после загрузки
OnBootSec=10min
# Затем каждые 6 часов после последнего запуска
OnUnitActiveSec=6h
# Если пропущено — запустить при следующей возможности
Persistent=true

[Install]
WantedBy=timers.target

Комбинирование монотонных и календарных таймеров в одном файле:

[Timer]
# Запустить через 5 минут после загрузки
OnBootSec=5min
# И по расписанию каждый час
OnCalendar=*:00:00
Persistent=true

Монотонные таймеры гарантируют минимальный интервал между запусками — если задача занимает 2 часа, OnUnitActiveSec=6h запустит следующую через 6 часов после завершения, а не по абсолютному расписанию.

Управление и мониторинг таймеров

Базовые команды для работы с таймерами:

# Список всех таймеров
systemctl list-timers --all

# Статус конкретного таймера
systemctl status cleanup.timer

# Логи связанного сервиса
journalctl -u cleanup.service --since today

# Ручной запуск (для тестирования)
sudo systemctl start cleanup.service

# Временное отключение
sudo systemctl stop cleanup.timer
sudo systemctl disable cleanup.timer

Вывод list-timers показывает: когда сработает следующий раз, когда сработал в последний раз, и сколько времени осталось:

NEXT                        LEFT          LAST                        PASSED      UNIT
Wed 2026-04-08 03:00:00 MSK 4h 32min left Tue 2026-04-07 03:14:22 MSK 19h ago     cleanup.timer
Wed 2026-04-08 00:00:00 MSK 1h 32min left Tue 2026-04-07 00:00:00 MSK 22h ago     logrotate.timer

Уведомления при сбое

Настройте уведомления при неудачном выполнении задачи:

# /etc/systemd/system/notify-failure@.service
[Unit]
Description=Уведомление о сбое %i

[Service]
Type=oneshot
ExecStart=/usr/local/bin/notify-admin.sh %i

Добавьте в основной сервис:

[Unit]
OnFailure=notify-failure@%n.service

Скрипт /usr/local/bin/notify-admin.sh:

#!/bin/bash
UNIT="$1"
STATUS=$(systemctl status "$UNIT" 2>&1 | head -20)
curl -s -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" \
  -d chat_id="$CHAT_ID" \
  -d text="Сбой задачи: $UNIT
$STATUS" \
  -d parse_mode="HTML"

Transient timers: одноразовые задачи

Для разовых задач не нужно создавать файлы юнитов — используйте systemd-run:

# Запустить команду через 30 минут
sudo systemd-run --on-active=30min /usr/local/bin/backup.sh

# Запустить в конкретное время
sudo systemd-run --on-calendar="2026-04-08 22:00:00" \
    --description="Ночная миграция БД" \
    /opt/scripts/migrate-db.sh

# С ограничением ресурсов
sudo systemd-run --on-active=5min \
    --property=CPUQuota=50% \
    --property=MemoryMax=1G \
    /usr/bin/python3 /opt/scripts/report.py

Transient timer автоматически удаляется после выполнения. Удобно для отложенных задач обслуживания: «выполнить ребут через 2 часа», «запустить миграцию в 3:00 ночи».

Проверьте созданные transient таймеры:

systemctl list-timers --all | grep run-

Миграция с cron на systemd timers

Пошаговый план миграции существующих задач cron:

  1. Выгрузите текущий crontab: crontab -l > cron-backup.txt
  2. Для каждой задачи создайте пару .timer + .service
  3. Протестируйте ручным запуском: systemctl start task.service
  4. Активируйте таймер: systemctl enable --now task.timer
  5. Убедитесь в работоспособности через journalctl
  6. Удалите задачу из crontab

Таблица соответствия cron → OnCalendar:

CronOnCalendarОписание
*/5 * * * **:0/5Каждые 5 минут
0 * * * *hourlyКаждый час
0 2 * * **-*-* 02:00:00Ежедневно в 02:00
0 0 * * 0Sun *-*-* 00:00:00Каждое воскресенье
0 0 1 * **-*-01 00:00:00Первого числа месяца
30 4 1,15 * **-*-01,15 04:30:001-го и 15-го в 04:30

Часто задаваемые вопросы

Да, для подавляющего большинства задач. Systemd timers покрывают все сценарии cron и добавляют возможности, недоступные в cron (зависимости, cgroups, Persistent). Единственный нюанс — некоторые пакеты ожидают cron (например, /etc/cron.daily/), но systemd-cron bridge или пакет run-parts решают это.

В секции [Service] укажите User=username и Group=groupname. Или разместите юниты в ~/.config/systemd/user/ и управляйте через systemctl --user. Пользовательские таймеры работают только при активном сеансе, если не включён loginctl enable-linger username.

Если сервер был выключен в момент запланированного запуска, Persistent=true запустит задачу сразу после загрузки. Без этого параметра пропущенное срабатывание будет просто потеряно. Аналог в cron — anacron, но systemd реализует это нативно и надёжнее.

Systemd автоматически предотвращает запуск второго экземпляра, если предыдущий ещё работает. Если таймер сработал, а сервис занят — запуск будет отложен. Для cron это классическая проблема, решаемая через flock. В systemd это поведение по умолчанию без дополнительной настройки.

Нужна помощь с настройкой?

Специалисты АйТи Фреш помогут с внедрением и настройкой — 15+ лет опыта, обслуживание от 15 000 ₽/мес

📞 Связаться с нами
#systemd timers#cron замена#планирование задач Linux#systemd timer настройка#OnCalendar#journalctl таймер#systemd transient timer#monotonic timer
Комментарии 0

Оставить комментарий

загрузка...