Регулярное задание через systemd timer: расписание и проверка выполнения

Раз в час сервер должен обновлять локальный отчёт. Вручную скрипт работает, но при автоматическом запуске непонятно, выполнялся ли он сегодня и что произошло после ночной перезагрузки. Для такой задачи удобно связать два systemd unit: один описывает работу, другой — момент её запуска. Тогда журнал относится к конкретному сервису, а расписание можно посмотреть отдельно.

В примере используется Linux с systemd в качестве системного менеджера. Для контейнера, где systemd не запущен как менеджер, этот способ напрямую не подходит. Сначала отладим безопасную демонстрацию: сервис печатает время в журнал. Затем вместо команды даты можно подключить уже проверенный скрипт обновления отчёта.

Опишите одно выполнение

Сохраните первый файл как /etc/systemd/system/report-refresh.service. Для системных unit потребуются административные права. Type=oneshot означает короткую работу: systemd ждёт завершения команды и фиксирует её результат. В отличие от постоянно работающего HTTP-сервиса, здесь нормальное состояние между запусками — отсутствие процесса.

[Unit]
Description=Record report refresh invocation

[Service]
Type=oneshot
ExecStart=/usr/bin/date --iso-8601=seconds

Путь к date проверьте на своей системе. Команда не создаёт отчёт, а даёт легко узнаваемую запись для проверки самого расписания. Когда подключаете настоящую обработку, укажите отдельного пользователя через User, необходимые пути и источник конфигурации. systemd не запускает интерактивную оболочку пользователя и не подхватывает её окружение автоматически.

Команда должна возвращать ненулевой статус при неудаче. Если скрипт записал ошибку, но завершился с нулём, systemd увидит успешную работу. Для цепочки действий лучше сделать отдельный исполняемый скрипт с явной обработкой ошибок, чем пытаться поместить shell-конвейер в ExecStart без понимания способа его выполнения.

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

Второй файл называется report-refresh.timer. Совпадение основной части имени связывает timer с сервисом. OnCalendar задаёт календарное расписание; hourly означает запуск по часовым границам. Persistent позволяет после простоя выполнить пропущенную календарную работу при следующей активации таймера.

[Unit]
Description=Refresh report every hour

[Timer]
OnCalendar=hourly
Persistent=true
AccuracySec=1min

[Install]
WantedBy=timers.target

Persistent не воспроизводит каждый пропущенный час отдельным запуском. Для отчёта, который строит актуальное состояние, одного выполнения обычно достаточно. Для учёта каждого расчётного периода сами периоды нужно хранить в приложении и выбирать необработанные: расписание лишь сообщает, когда стоит проснуться.

AccuracySec допускает сдвиг срабатывания в указанном окне. Это подходит периодическому отчёту, но не задаче, у которой существенна точная секунда. Календарное время также зависит от часов и часового пояса сервера. Перед включением посмотрите, какое ближайшее срабатывание вычисляет systemd, особенно для ежедневных локальных расписаний и переходов времени.

Сначала проверьте, затем включите

После сохранения файлов проверьте их разбор и вычисляемое расписание. Только затем загрузите новые определения, выполните сервис вручную и включите timer. Команды изменения состояния выполняются администратором на подготовленном учебном сервере.

systemd-analyze verify /etc/systemd/system/report-refresh.service /etc/systemd/system/report-refresh.timer
systemd-analyze calendar hourly
sudo systemctl daemon-reload
sudo systemctl start report-refresh.service
sudo systemctl enable --now report-refresh.timer
systemctl list-timers report-refresh.timer
journalctl -u report-refresh.service --since today

В журнале ручного запуска должна появиться текущая дата. В списке таймеров — время следующего и последнего срабатывания. После планового запуска проверьте новую запись журнала. У активного таймера и успешной последней работы разные значения: timer может продолжать ждать, хотя предыдущая команда завершилась ошибкой.

Для рабочего задания заранее выберите, кто заметит неудачу. Минимальная проверка — ненулевой статус сервиса и возраст последнего готового результата. Если отчёт должен обновляться каждый час, отсутствие свежего файла за несколько периодов требует внимания даже при активном timer. Порог выбирают по допустимой задержке данных. Уведомление можно подключить штатным мониторингом проекта, сохранив журнал команды для объяснения причины.

Решите, что делать с долгой работой

Если тот же сервис ещё активен к следующему срабатыванию, timer не создаёт второй экземпляр этого сервиса. Это удобно для защиты от перекрытия одного unit. Но другой unit или ручной запуск самого скрипта остаются отдельными путями; для общего ресурса может понадобиться блокировка в скрипте или в приложении.

Долгое выполнение также означает, что привычная частота обновления больше не выдерживается. Смотрите длительность работы и возраст готового отчёта. При неуспешном обновлении предыдущий отчёт можно оставить доступным с отметкой времени, чтобы клиент отличал устаревшие данные от свежих. Повторный запуск должен иметь осмысленное поведение и не удваивать побочные действия.

Если задача запускается в контейнере как отдельная команда, сначала выберите подходящий способ run или exec. Это определяет, какой процесс и какое окружение будет запускать ваш планировщик.

Когда расписание проверено, следующий полезный шаг — сам надёжный скрипт: аргументы, пути, доступ к файлам и статус ошибки. Курс «Bash Linux + Git» включает написание скриптов, переменные и аргументы, условия, управление процессами и автоматизацию через cron и at. Эта практика помогает подготовить команду, которую затем запускает выбранный планировщик. Откройте программу и укрепите основу для своих регулярных операций. Настройку timer сохраняйте рядом с проверяемым скриптом, чтобы изменение расписания проходило тот же обзор в Git.

Продолжить на практике