Skip to content

ADR 0031: автономная установка и обновление стабильными релизами ​

Статус: accepted. Owner: Ian Panaev. Дата: 2026-09-25.

Дополнение 2026-09-26: ADR 0038 добавляет зависимость deploy → contracts и ограниченный mailbox для удалённого управления, сохраняя привилегированный supervisor вне HTTP API.

Решение ​

apps/deploy — отдельная точка сборки управления установкой, без импортов других workspaces. Она не входит в HTTP API и не принимает удалённые команды от клиентов. Узкий UpdatePort отделяет порядок переключения от GitHub, файловой системы и менеджера служб. API/worker запускаются как отдельные процессы; их предметная архитектура не меняется.

В релиз включаются скомпилированные приложения, статический UI и production-зависимости из lockfile. Сборка на сервере и git pull в работающий каталог не выполняются. Runtime ZIP переносим между поддерживаемыми ОС: workspace links материализуются обычными файлами. Новая нативная зависимость потребует отдельных platform artifacts и пересмотра этого решения.

Код находится в releases/version; конфигурация, секреты и данные — за пределами releases. Служба не может менять код и GitHub credential. Привилегии обновления принадлежат локальному администратору/планировщику. systemd и WinSW обеспечивают перезапуск API/worker; контейнерами управляет restart policy движка.

Обновления opt-in, только опубликованные stable GitHub Releases. Pin блокирует плановые обновления. Подмена уже установленной версии и downgrade запрещены. SHA-256 защищает от повреждения/несовпадения опубликованных файлов, но не заменяет подпись: доверенная граница — права публикации в репозитории и TLS GitHub. Токен чтения приватного репозитория хранится отдельно; при перенаправлениях не передаётся CDN.

Переходы и отказ ​

Download → checksum → ограниченное безопасное извлечение → подготовка образа → journal/prepared → остановка → переключение installation.json → старт → несколько readiness probes и проверка процесса worker → committed. Один lock запрещает параллельные операции. Журнал и указатель записываются через fsync и rename; на POSIX синхронизируется родительский каталог. Windows не предоставляет эквивалент directory fsync через Node, поэтому после отключения питания требуется проверить журнал.

При той же схеме БД обновление не запускает миграции, что позволяет вернуть предыдущий код. При ошибке rollback пишется recovery-required. После аварии stale lock не захватывается автоматически: оператор проверяет процессы и журнал, затем запускает recover. Данные и старые релизы автоматически не удаляются.

Ошибка записи журнала после остановки служб не отменяет попытку rollback: сохранённая фаза prepared/stopped уже содержит предыдущую версию. Откат повторно останавливает службы, восстанавливает указатель и проверяет запуск. Если итоговый журнал записать не удалось, команда сообщает об этом как об ошибке и требует проверки перед повтором; успешный rollback не выдаётся за успешное обновление. При ошибках самого отката сохранение recovery-required выполняется по возможности, исходный отказ восстановления не подменяется ошибкой журналирования.

Команда развёртывания имеет deadline 15 минут. При превышении завершается дерево процессов: отдельная process group на POSIX, taskkill /T /F на Windows. Runner ждёт завершения дочернего процесса и подтверждения остановки дерева не более 10 секунд. Если подтверждения нет, автоматический rollback не продолжается, operation.lock сохраняется, а recovery-required пишется по возможности. Оператор проверяет оставшиеся процессы, состояние служб и журнал перед удалением lock и ручным восстановлением. На POSIX неубранные zombie-процессы также могут привести к такому консервативному результату. Остановка CLI не отменяет уже принятые задания Docker daemon или systemd: после timeout их состояние нужно отдельно сверить, даже если локальное дерево успешно остановлено.

Изменение схемы выполняет отдельный maintenance upgrade с явной ссылкой на запись о backup. Это подтверждение оператора, не автоматическая проверка качества копии. После начала миграции автоматический возврат старых бинарников запрещён: требуется завершить обслуживание либо восстановить согласованные БД/файлы.

Проверка readiness повторяет обычный отказ worker probe, но немедленно передаёт ошибку неподтверждённой остановки (включая цепочку cause) вызывающему updater. Успешный следующий probe не доказывает завершение предыдущего процесса и не разрешает снимать installation lock.

Ограничения ​

Профиль один writer + один completion worker. Обновление имеет окно недоступности: активные потоки получают штатную остановку, затем могут потребовать resume со стороны клиента. Это не rolling update и не HA. Healthcheck не превращается в автоматический restart при любой ошибке БД/диска: restart policy относится к завершению процесса, мониторинг доступности остаётся отдельным.

ОС без systemd используют Compose или внешнего supervisor. Windows installer — x64; Linux glibc — x64/arm64. Для Podman нужен совместимый compose provider; его наличие не доказывает приёмку каждой реализации. TLS, backup и двухсерверное fencing требуют эксплуатационной настройки и проверки стенда.

Arkvory · ProAnimaStudio