Установка

Обновление и откат

Порядок действий при релизе, почему миграции необратимы и что делать после неудачного обновления.

На этой странице · 5

Обновление стенда — это код, схема базы и перезапуск процессов. Код и процессы возвращаются назад легко, схема — нет. С этого и начнём.

Миграции необратимы

prisma migrate deploy применяет неприменённые миграции и не умеет их отменять. Обратных миграций в репозитории нет. Значит:

  • git revert вернёт код, но не схему. Старый код увидит новую схему и, если миграция что-то удалила или переименовала, сломается.
  • Единственный полный откат — восстановление дампа плюс выкатка того коммита, которому этот дамп соответствует.
  • Миграцию, ломающую текущий код, разводите на два релиза: сначала совместимое изменение схемы, потом код, который на него опирается.

Дамп снимается до обновления, а не после

Восстановление из дампа возвращает базу в состояние на момент снимка. Всё, что произошло после, потеряно — это цена отката, и она тем меньше, чем свежее дамп.

Обновление в контейнерах

  1. 1

    Снимите дамп

    docker exec apistend-postgres pg_dump -U apistend -d apistend --format=custom \
      > /var/backups/apistend-$(date +%F).pgdump
    
  2. 2

    Обновите код и пересоберите образ

    git pull
    docker compose build
    

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

  3. 3

    Перезапустите

    docker compose up -d
    

    Контейнер api при старте сам выполняет prisma migrate deploy, потом поднимает сервер. web дождётся, пока api ответит на /health.

  4. 4

    Проверьте

    curl -s localhost:8080/health
    

    И зайдите в кабинет: /health не проверяет ни вход, ни отрисовку страниц.

Обновление из исходников

Порядок тот же, но шаги делаются руками и в строгой последовательности:

git pull
pnpm install --frozen-lockfile --prod=false
pnpm --filter @apistend/api exec prisma generate
pnpm --filter @apistend/api exec prisma migrate deploy
pnpm --filter @apistend/web run build

--prod=false обязателен: при NODE_ENV=production pnpm выбросит prisma и dotenv, а dotenv импортируется в рантайме. Собирать API не нужно и нечем — он запускается прямо с исходников через node --experimental-strip-types.

Кабинет и шлюз перезапускаются независимо. Мок-шлюз во время сборки кабинета продолжает отвечать, поэтому логичный порядок — собрать кабинет, потом перезапустить оба.

Если релиз не удался

  1. 1

    Миграция упала

    Схема осталась в промежуточном состоянии, а api не стартовал: точка входа работает с set -e, и сервер после неудачной миграции не запускается. Кабинет тоже не поднимется — он ждёт здоровья api. Разбирайтесь с миграцией на месте; молча пропускать её нельзя.

  2. 2

    Миграция прошла, а код сломался

    Верните предыдущий коммит и пересоберите. Схема останется новой — это работает, пока миграция была совместимой. Если нет, переходите к следующему шагу.

  3. 3

    Нужен полный откат

    Восстановите дамп и выкатите тот коммит, при котором он снят:

    docker compose stop api web
    docker exec -i apistend-postgres pg_restore -U apistend -d apistend --clean --if-exists \
      < /var/backups/apistend-2026-09-09.pgdump
    git checkout <коммит>
    docker compose up -d --build
    

Что не переживает перезапуск

  • Серии событий. Расписание живёт в памяти процесса. При старте незавершённые серии помечаются прерванными — оставить их в состоянии «идёт» значило бы показывать в интерфейсе неправду.
  • Сессии туннеля. apistend listen придётся запустить заново.
  • Кеши. Кеш тел ответов и кеш разбора ключей прогреваются заново; первые запросы после рестарта медленнее.

Журнал запросов и приращения счётчиков ключей при этом не теряются: на SIGINT и SIGTERM сервер дописывает накопленные буферы и только потом закрывается. Убийство процесса по SIGKILL этой гарантии не даёт.