Requires не задаёт порядок: устраняем гонку двух systemd-служб
Обработчик читает индекс, который при загрузке готовит другая служба. В его unit уже добавили Requires=index-build.service, однако после перезагрузки индекс иногда ещё отсутствует. Требование запустить другую службу само по себе не задаёт последовательность выполнения.
Проверить две независимые связи
systemctl show report.service -p Requires -p Wants -p After -p Before systemctl cat report.service index-build.service journalctl -b -u report.service -u index-build.service -o short-monotonic
Requires и Wants отвечают за включение других units в операцию. After и Before определяют порядок между units, которые уже участвуют в запуске. After само по себе не запускает указанную службу. Поэтому для обязательной предварительной работы часто нужны обе связи.
[Unit]
Requires=index-build.service
After=index-build.serviceЭто фрагмент потребителя report.service. Он имеет смысл, если готовность index-build корректно описана его типом службы. Для разового построения индекса подходит Type=oneshot: стартовая операция завершится после выхода команды. Для долгоживущего производителя порядок зависит от того, когда его unit считается запущенным.
Отделить запуск процесса от готовности
Если производитель использует Type=simple и ещё десять секунд строит индекс внутри уже работающего процесса, After не узнает о завершении этой внутренней операции. Зависимость будет соблюдена на уровне модели systemd, а прикладная гонка останется. Требуется корректный сигнал готовности, выделенный подготовительный шаг или поддерживаемое ожидание ресурса.
Например, монотонный журнал показывает старт index-build на 2,1 секунды, запуск report на 2,2 и сообщение «index ready» на 12,4. Это прямое свидетельство неверной границы готовности. Увеличение sleep у потребителя лишь привязывает работу к случайной длительности и может снова сломаться на медленном диске.
Учесть отказ зависимости
Requires с соответствующим After помогает не запускать потребителя, когда необходимая стартовая операция зависимости завершилась неудачей. Но жизненный цикл при неожиданном исчезновении ресурса требует отдельного решения. Для более жёсткой связи существует BindsTo вместе с порядком; для совместного перезапуска могут использоваться другие отношения. Выбирайте их по требуемому поведению, а не добавляйте все сразу.
Определения отношений есть в systemd.unit. Важный практический вопрос: должен ли потребитель остановиться, если производитель перестал работать, или он может использовать уже созданный индекс? Ответ определяет нужную связь.
Проверить граф без удачного случая
На стенде замедлите построение индекса поддерживаемым способом, затем имитируйте его ошибку. Потребитель должен начинать работу после реальной готовности и ясно отказываться при отсутствии обязательного результата. После исправления снова снимите совместный журнал в монотонном времени.
Проверьте отсутствие циклов в зависимостях: если одна служба After второй, а вторая после первой, порядок не может быть выполнен. systemd-analyze verify помогает найти ошибки unit, но тест фактической готовности всё равно нужен.
В программе Linux и Bash для DevOps-инженеров настройка сервиса под systemd сопровождается чтением журналов. Откройте программу, чтобы строить такие зависимости вокруг понятного жизненного цикла приложения.
Ещё по теме
Продолжить на практике
- Linux и Bash для DevOps-инженеров ↗
Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.
