Сбой systemd-службы быстро исчезает: собираем контекст через OnFailure

Регулярный импорт упал ночью. Утром журнал ещё есть, но временный каталог уже очищен, а файл входных параметров заменён следующим запуском. Искать причину приходится по обрывкам. Удобно привязать короткий сбор диагностического контекста к состоянию службы, чтобы он выполнялся рядом с моментом отказа.

Для этого у systemd есть OnFailure: в секции Unit можно указать другую службу, которая будет запущена при переходе исходной в failed. Обработчик здесь не чинит импорт и не повторяет опасное действие. Его задача — сохранить небольшую сводку, которую потом можно сопоставить с данными приложения. Чем проще такой обработчик, тем больше шансов получить полезный след при следующем сбое.

Отделить работу от диагностики

Для конкретной службы можно использовать отдельный oneshot-unit без шаблонов и динамического построения команды. Так связь читается прямо из конфигурации.

# import.service
[Unit]
OnFailure=import-diagnostics.service

# import-diagnostics.service
[Service]
Type=oneshot
ExecStart=/usr/bin/journalctl -u import.service -n 100 --no-pager
StandardOutput=journal

Этот обработчик записывает последние сообщения импорта в собственный журнал. Он даёт понятную отправную точку; для постоянного хранения вложений вместо journalctl понадобится подготовленный скрипт и каталог с ограниченным доступом. В него можно сохранять идентификатор входной партии, версию приложения и список файлов. Содержимое секретов и весь входной набор копировать без разбора не стоит: это затрудняет чтение и создаёт лишние копии данных.

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

Проверить переход состояния

На учебном unit вызовите контролируемую ошибку и убедитесь, что запускается именно обработчик. Посмотрите journalctl -u import-diagnostics.service и статус исходной службы. Успешный обработчик не должен превращать неудачный импорт в успешный: это два разных результата. Также проверьте штатное выполнение, при котором диагностический unit запускаться не должен.

Если у исходной службы настроены автоматические перезапуски, проверьте полный жизненный цикл на своей версии systemd. Момент окончательного failed и отдельные попытки рестарта — разные события. Для подробностей каждой попытки надёжнее сохранять контекст в приложении или подходящем stop-post обработчике, а OnFailure оставить реакцией на состояние unit.

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

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

За одной настройкой unit обычно стоит весь путь сопровождения приложения: отдельный пользователь, права на данные, сеть, журналы и повторяемые операции. В программе курса «Linux и Bash для DevOps-инженеров» эти задачи собраны вокруг учебного сервера с приложением под systemd. В практике предусмотрены Bash-скрипты проверки состояния и резервного копирования, а также runbook для воспроизводимых поломок. Это подходящее продолжение, если хочется связать отдельные команды в понятный порядок диагностики.

Посмотреть программу курса

Источник: официальная документация.

Другие задачи по теме: Запуск и жизненный цикл служб systemd.

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

  • Linux и Bash для DevOps-инженеров ↗

    Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.