Files
healthlog/docs/tasks/items/release-rollback-after-migration.md
T
av d79189be18 docs: документация переведена на канон av-dev-pm
- беклог и план переехали в docs/tasks (38 задач, 11 целей), слаги
  переименованы с транслита на английские, 85 ссылок поправлены
- conventions.md разобран в docs/conventions/, local-research.md — в
  docs/research/, review-journal.md — в docs/review.md с разделом настройки
  конвейера; заведены security.md, adr/ и .pm.json
- шаг docs.py check добавлен в task gate; поведение в architecture.md помечено
  девятью маркерами долга, database.md получил настройки с числовым значением
2026-08-03 17:14:53 +03:00

5.4 KiB

Чем откатывать релиз после наката миграции

Секция: инфра · Хук: Решено: копия файла базы перед накатом. Страж версии схемы делает возврат бинаря отказом, а понизить схему нечем · Теги: goal:deploy, question

Решение принято владельцем 2026-08-02: вариант (2) — копия файла базы перед накатом. Entrypoint контейнера копирует файл базы рядом до старта бинаря, откат = подмена файла. Down-блоки миграций при этом честно называются декорацией для локальной разработки, а не аварийным путём: ни один из них не исполнялся ни разу. Осталось решить при взятии — сколько копий держим и где. Задача естественно склеивается с деплоем. Ниже — исходная постановка блокера, она же ТЗ.

Вынуто ревью кода задачи «Дозакрыть находки ревью по слиянию сущностей» (проходы ops и negative, профиль deep).

Что именно решить

Та задача перенесла в store.Open стража версии схемы: база новее бинаря — отказ на старте. Решение принято владельцем и здесь не пересматривается. Но у него есть следствие, которое до сих пор нигде не было записано:

после того как новый бинарь накатил миграцию, возврат старого бинаря приёма не чинит. Он теперь отказывается стартовать, а понизить схему нечем:

  • подкоманды миграции у бинаря нет (serve, reindex, healthcheck);
  • goose CLI в образ не кладётся;
  • блоки -- +goose Down в миграциях написаны, но ни один тест их не исполняет, и на рабочей базе они не выполнялись ни разу (DROP COLUMN в SQLite через modernc.org/sqlite не проверялся вовсе);
  • restart: unless-stopped превращает отказ в цикл перезапуска, а телефон всё это время шлёт в закрытый порт и не перешлёт потом.

То есть аварийный путь придётся изобретать в момент аварии, при остановленном приёме. Цена простоя для метрик закрывается широким и глубоким проходами синхронизации; для stateOfMind не закрывается ничем — у него доставки HAE единственный источник.

Вопросы

  1. Подкоманда healthlog migrate --down-to N. Цена: новая поверхность CLI плюс тест на Down каждой миграции (сейчас их нет, и DROP COLUMN в SQLite ведёт себя не так, как в постгресе). Зато откат становится операцией, а не импровизацией.
  2. Копия файла базы перед накатом — entrypoint контейнера делает cp рядом, откат = подмена файла. Цена: место (база растёт), плюс правило «сколько копий держим». Зато не требует ни кода, ни доверия к Down, а база производна от архива — потеря копии не смертельна.
  3. goose CLI в образ. Цена: образ перестаёт быть одним статическим бинарём, появляется вторая точка, знающая про схему.
  4. Ничего, но записать вслух: «понижение схемы не поддерживается, лечение — только выкатка вперёд». Цена: в аварии выбора нет.

Рекомендация

(2) плюс уже сделанная запись из (4). Копия файла — единственный вариант, который не требует доверять непроверенному коду ровно в тот момент, когда проверять некогда; а Down-блоки при этом честно называются декорацией для локальной разработки.

Что стоит, пока решения нет

Ничего: страж работает, и это правильно. Стоит только аварийный сценарий — он существует ровно в том виде, в каком описан выше. Строка «понижение схемы не поддерживается» уже записана в docs/architecture.md (раздел «Деплой»).