Skip to content

0067. Самовосстановление служб: падение, потеря владения и зависание ​

Статус: accepted. Owner: Ian Panaev. Дата: 2026-10-04.

Контекст ​

API, worker и агент резервных копий работают под супервизором платформы:

  • systemd: Restart=always, RestartSec=10, StartLimitIntervalSec=0;
  • WinSW и диспетчер служб Windows: onfailure restart, sc failure … restart/10000 с failureflag 1; последнее действие SCM повторяет при каждом следующем сбое;
  • Docker Compose: restart: unless-stopped.

Супервизор перезапускает процесс, который завершился. Падение (uncaught, OOM, kill) так и покрывалось. Потерю владения хранилищем или аренды API и worker уже переводили в выход с кодом 1. Незапрошенный выход с кодом 0 launcher превращает в 1, иначе SCM не считает его сбоем.

Не покрывалось зависание. Процесс с заблокированным event loop (бесконечный цикл, блокирующий вызов, зависание в нативном коде) не отвечает и не завершается. Ни systemd, ни SCM, ни Docker его не трогают; healthcheck Compose только помечает контейнер unhealthy.

Решение ​

Сторожевой поток в каждом процессе службы (API, worker, агент бэкапов):

  • главный поток раз в секунду увеличивает счётчик в SharedArrayBuffer;
  • отдельный worker_thread раз в секунду читает его;
  • если счётчик не менялся ARKVORY_WATCHDOG_SECONDS проверок подряд (по умолчанию 60), поток пишет в stderr запись process.stalled (stalledSeconds) и завершает процесс (SIGKILL; на Windows — завершение с кодом 1);
  • дальше супервизор поднимает процесс, как после падения.

Пропуски считаются по тикам самого сторожа, а не по часам. Когда машина спит или VM на паузе, оба потока стоят, и после пробуждения ложного срабатывания нет.

Код потока берёт встроенные модули через process.getBuiltinModule: eval-код работает и под CommonJS, и под ES-модулем родителя. Сбой самого сторожа не останавливает службу, а пишет process.watchdog_failed.

ARKVORY_WATCHDOG_SECONDS: 10–3600 секунд, 0 — выключено (для отладчика, который ставит процесс на паузу). Неверное значение — ошибка запуска.

Docker Desktop на Windows — приложение пользователя: до его запуска ни один контейнер не работает, какой бы ни была политика перезапуска. Установка Compose и status предупреждают, если в Docker Desktop выключен автозапуск при входе в систему.

Матрица ​

Что случилосьsystemdСлужбы WindowsDocker Compose
Падение, kill, OOMперезапуск через 10 сперезапуск через 10 сперезапуск с нарастающей паузой
Выход без запроса остановки (в т.ч. код 0)перезапускlauncher даёт код 1 → перезапускперезапуск
Потеря владения хранилищем или аренды (обрыв БД)выход 1 → перезапусквыход 1 → перезапусквыход 1 → перезапуск
Зависание главного потокасторож → перезапусксторож → перезапусксторож → перезапуск
БД недоступна при стартевыход 1, повтор каждые 10 свыход 1, повтор каждые 10 свыход 1, повтор с паузой
Перезагрузка машиныWantedBy=multi-user.targetавтозапуск (отложенный)при старте Docker; Docker Desktop — после входа пользователя с включённым автозапуском
Плановая остановка операторомне перезапускаетсяне перезапускаетсяdocker compose stop — не перезапускается

Последствия ​

  • Отладчик, поставивший службу на паузу дольше порога, получит её перезапуск; для отладки задайте ARKVORY_WATCHDOG_SECONDS=0.
  • Долгая синхронная работа в главном потоке дольше порога считается зависанием. Правила проекта и так запрещают блокировать event loop.
  • Агент PostgreSQL и сама БД отдельным сторожем не охвачены; их перезапускают те же супервизоры при падении.

Проверки ​

  • tests/event-loop-watchdog.test.mjs:
    • зависший процесс завершён с записью process.stalled;
    • короткие синхронные всплески и выключенный сторож процесс не трогают;
    • родитель как ES-модуль;
    • разбор настройки.
  • Гейт deployment-containers: главные потоки API, worker и агента ставятся на паузу через инспектор (SIGUSR1, Debugger.pause); сторож завершает их, Docker перезапускает, установка снова готова.
  • Гейт native-install (Linux systemd локально и на GitHub, Windows на GitHub): то же для установленных служб, на Windows инспектор открывается через process._debugProcess из сеанса 0 (разовая задача SYSTEM): службы публикуют обработчик отладки только в своём сеансе.
  • Падения, три подряд, и плановая остановка — прежние гейты deployment-services и native-install.
  • tests/engine-autostart.test.mjs: чтение настройки автозапуска Docker Desktop.

Arkvory · ProAnimaStudio