Files
call-center/docs/runbooks/postgres-dev-cutover.md
T

9.6 KiB
Raw Blame History

PostgreSQL Dev Cutover

Этот runbook описывает безопасный перевод dev-окружения с SQLite на PostgreSQL без переноса старых данных.

Что считается "без простоя"

В этом проекте без переноса SQLite-данных безостановочный cutover означает не hot-swap одной и той же базы, а:

  1. поднять новый PostgreSQL-backed stack параллельно;
  2. прогнать smoke на новом stack;
  3. переключить dev-трафик на новый gateway;
  4. оставить старый SQLite stack живым до подтверждения GO;
  5. при проблеме вернуть трафик обратно без восстановления данных.

Если сейчас у dev только один instance и нет возможности держать parallel stack, нужен короткий maintenance window.

Scope

Включает:

  • подготовку PostgreSQL и RabbitMQ;
  • применение SQL migrations;
  • запуск сервисов в SCHEMA_MANAGEMENT_MODE=migrations;
  • smoke-проверки до и после переключения;
  • rollback на старый SQLite-backed dev stack.

Не включает:

  • перенос данных из SQLite;
  • cleanup legacy SQLite-path;
  • production cutover.

Required Inputs

  • DEV_GATEWAY_OLD
  • DEV_GATEWAY_NEW
  • POSTGRES_DATABASE_URL
  • APP_TOKEN_SECRET
  • PUBLIC_SWITCH_METHOD
    • DNS
    • reverse proxy
    • load balancer route
  • RABBITMQ_URL

Рекомендуемые значения для локально-управляемого dev:

  • POSTGRES_DATABASE_URL=postgresql://mvp:mvp@<postgres-host>:5432/mvpcc
  • SCHEMA_MANAGEMENT_MODE=migrations
  • env template: .env.postgres.local.template

Phase 0 - Preconditions

Подтвердить перед началом:

  1. Текущий SQLite-backed dev stack стабилен.
  2. Перенос данных не нужен.
  3. PostgreSQL доступен по сети с host, где запускаются сервисы.
  4. RabbitMQ доступен по сети, если в dev нужен EVENT_BUS_ENABLED=1.
  5. Новая dev-конфигурация использует:
    • DATABASE_URL=postgresql://...
    • SCHEMA_MANAGEMENT_MODE=migrations
  6. Старый SQLite stack не останавливается до завершения smoke на новом stack.

Phase 1 - Preflight

На будущем PostgreSQL-backed dev host:

  1. Проверить Python зависимости:
python -m pip install -r requirements.txt
  1. Подготовить env-файл:

    • скопировать .env.postgres.local.template
    • заполнить DATABASE_URL, APP_TOKEN_SECRET, интеграционные URL и при необходимости AI/Telegram/WhatsApp переменные
  2. Запустить DB-only preflight:

python scripts\postgres_dev_preflight.py --env-file .env.postgres.local.template
  1. Убедиться, что mode не legacy:
SCHEMA_MANAGEMENT_MODE=migrations
  1. Применить миграции в PostgreSQL:
python scripts\migrate_core_db.py

Ожидается:

  • миграции применились без ошибок;
  • в PostgreSQL появилась таблица schema_migrations;
  • сервисы ещё не стартовали.

Phase 2 - Bring Up Parallel Stack

Поднять новый stack параллельно старому.

Если запуск локальный:

python scripts\local_stack.py start `
  --runtime-dir .local_stack_pg `
  --env-file .env.postgres.local.template `
  --force-restart

Если это dev server / VM:

  1. развернуть те же сервисы в отдельный deployment set;
  2. прокинуть им:
    • DATABASE_URL=postgresql://...
    • SCHEMA_MANAGEMENT_MODE=migrations
  3. не направлять внешний dev-трафик на новый gateway до завершения smoke.

Важно:

  • новый stack должен использовать отдельный runtime/log directory;
  • старый SQLite-backed stack остаётся доступным;
  • нельзя смешивать новый dev-трафик со старым gateway до smoke.

Phase 3 - Smoke Before Switch

Выполнить проверки на DEV_GATEWAY_NEW.

Сначала прогнать HTTP-aware preflight:

python scripts\postgres_dev_preflight.py `
  --env-file .env.postgres.local.template `
  --base-url http://127.0.0.1:8080
  1. Health:
python scripts\live_smoke_gate12.py --base-url http://<DEV_GATEWAY_NEW> --database-url <POSTGRES_DATABASE_URL>
  1. Focused PostgreSQL smoke:
pytest -q tests/test_postgres_readiness.py
  1. Дополнительно проверить вручную:
  • GET /proxy/auth/health
  • GET /proxy/interaction/health
  • GET /proxy/voice/health
  • GET /proxy/ai-voice-runtime/health
  • открыть http://<DEV_GATEWAY_NEW>/operator
  1. Если в dev включён event bus:
  • проверить подключение к RabbitMQ;
  • убедиться, что event-bus-service поднимается в healthy;
  • убедиться, что новые записи появляются в event_outbox.

GO в следующую фазу только если:

  • health green;
  • smoke green;
  • новый stack не пытается auto-create schema на старте;
  • нет ошибок вида run python scripts/migrate_core_db.py после фактического применения миграций.

Phase 4 - Traffic Switch

Переключение выполняется только после успешного Phase 3.

Рекомендуемый порядок:

  1. уменьшить TTL у dev DNS / подготовить proxy route заранее;
  2. переключить DEV_GATEWAY на DEV_GATEWAY_NEW;
  3. не останавливать старый SQLite stack;
  4. сразу после switch выполнить быстрый post-switch smoke.

Примеры post-switch smoke:

python scripts\live_smoke_gate12.py --base-url http://<DEV_GATEWAY_PUBLIC> --database-url <POSTGRES_DATABASE_URL>

Проверить руками:

  • логин;
  • создание interaction;
  • digital thread/message flow;
  • voice event ingest;
  • создание voice AI session.

Phase 5 - Stabilization Window

В течение первых 15-30 минут после switch:

  1. наблюдать логи gateway и сервисов;
  2. следить за ошибками подключения к PostgreSQL;
  3. следить за ошибками schema mismatch;
  4. следить за ошибками блокировок/unique conflict в voice transcript path;
  5. сравнивать user-visible поведение со старым dev stack.

Если всё стабильно:

  1. объявить GO;
  2. зафиксировать, что dev теперь PostgreSQL-backed;
  3. оставить SQLite stack выключенным, но не удалённым до конца рабочего дня.

Rollback

Rollback делается только через возврат трафика на старый SQLite-backed stack.

Триггеры rollback:

  • новый gateway не проходит smoke;
  • сервисы падают на startup;
  • критичный API path broken;
  • UI не работает;
  • ошибки подключения к PostgreSQL не устраняются быстро;
  • event bus / voice path деградирует.

Шаги rollback:

  1. вернуть DEV_GATEWAY_PUBLIC на DEV_GATEWAY_OLD;
  2. убедиться, что старый SQLite stack всё ещё жив;
  3. выполнить быстрый smoke на старом stack;
  4. запретить новый трафик на PostgreSQL-backed stack;
  5. собрать логи с нового stack.

Rollback успешен, если:

  • dev UI снова открывается на старом gateway;
  • CRUD и smoke снова зелёные;
  • команда работает на старом dev без дополнительных действий.

Cutover Sheet

Перед cutover заполнить:

  • время старта;
  • кто выполняет switch;
  • DEV_GATEWAY_OLD;
  • DEV_GATEWAY_NEW;
  • POSTGRES_DATABASE_URL;
  • результат preflight;
  • результат smoke до switch;
  • время switch;
  • результат smoke после switch;
  • GO / ROLLBACK;
  • короткий список замечаний.

Minimal Command Sequence

Если нужен самый короткий practical path для dev:

python scripts\migrate_core_db.py
python scripts\postgres_dev_preflight.py --env-file .env.postgres.local.template
python scripts\local_stack.py start --runtime-dir .local_stack_pg --env-file .env.postgres.local.template --force-restart
python scripts\postgres_dev_preflight.py --env-file .env.postgres.local.template --base-url http://127.0.0.1:8080
pytest -q tests/test_postgres_readiness.py
python scripts\live_smoke_gate12.py --database-url postgresql://mvp:mvp@localhost:5432/mvpcc

После этого:

  1. переключить dev gateway/public route на новый stack;
  2. прогнать smoke ещё раз уже через публичный dev URL;
  3. оставить старый SQLite stack как rollback target.