9.6 KiB
PostgreSQL Dev Cutover
Этот runbook описывает безопасный перевод dev-окружения с SQLite на PostgreSQL без переноса старых данных.
Что считается "без простоя"
В этом проекте без переноса SQLite-данных безостановочный cutover означает не hot-swap одной и той же базы, а:
- поднять новый PostgreSQL-backed stack параллельно;
- прогнать smoke на новом stack;
- переключить dev-трафик на новый gateway;
- оставить старый SQLite stack живым до подтверждения GO;
- при проблеме вернуть трафик обратно без восстановления данных.
Если сейчас у 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_OLDDEV_GATEWAY_NEWPOSTGRES_DATABASE_URLAPP_TOKEN_SECRETPUBLIC_SWITCH_METHOD- DNS
- reverse proxy
- load balancer route
RABBITMQ_URL
Рекомендуемые значения для локально-управляемого dev:
POSTGRES_DATABASE_URL=postgresql://mvp:mvp@<postgres-host>:5432/mvpccSCHEMA_MANAGEMENT_MODE=migrations- env template: .env.postgres.local.template
Phase 0 - Preconditions
Подтвердить перед началом:
- Текущий SQLite-backed dev stack стабилен.
- Перенос данных не нужен.
- PostgreSQL доступен по сети с host, где запускаются сервисы.
- RabbitMQ доступен по сети, если в dev нужен
EVENT_BUS_ENABLED=1. - Новая dev-конфигурация использует:
DATABASE_URL=postgresql://...SCHEMA_MANAGEMENT_MODE=migrations
- Старый SQLite stack не останавливается до завершения smoke на новом stack.
Phase 1 - Preflight
На будущем PostgreSQL-backed dev host:
- Проверить Python зависимости:
python -m pip install -r requirements.txt
-
Подготовить env-файл:
- скопировать .env.postgres.local.template
- заполнить
DATABASE_URL,APP_TOKEN_SECRET, интеграционные URL и при необходимости AI/Telegram/WhatsApp переменные
-
Запустить DB-only preflight:
python scripts\postgres_dev_preflight.py --env-file .env.postgres.local.template
- Убедиться, что mode не legacy:
SCHEMA_MANAGEMENT_MODE=migrations
- Применить миграции в 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:
- развернуть те же сервисы в отдельный deployment set;
- прокинуть им:
DATABASE_URL=postgresql://...SCHEMA_MANAGEMENT_MODE=migrations
- не направлять внешний 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
- Health:
python scripts\live_smoke_gate12.py --base-url http://<DEV_GATEWAY_NEW> --database-url <POSTGRES_DATABASE_URL>
- Focused PostgreSQL smoke:
pytest -q tests/test_postgres_readiness.py
- Дополнительно проверить вручную:
GET /proxy/auth/healthGET /proxy/interaction/healthGET /proxy/voice/healthGET /proxy/ai-voice-runtime/health- открыть
http://<DEV_GATEWAY_NEW>/operator
- Если в 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.
Рекомендуемый порядок:
- уменьшить TTL у dev DNS / подготовить proxy route заранее;
- переключить
DEV_GATEWAYнаDEV_GATEWAY_NEW; - не останавливать старый SQLite stack;
- сразу после 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:
- наблюдать логи gateway и сервисов;
- следить за ошибками подключения к PostgreSQL;
- следить за ошибками
schema mismatch; - следить за ошибками блокировок/unique conflict в voice transcript path;
- сравнивать user-visible поведение со старым dev stack.
Если всё стабильно:
- объявить GO;
- зафиксировать, что
devтеперь PostgreSQL-backed; - оставить SQLite stack выключенным, но не удалённым до конца рабочего дня.
Rollback
Rollback делается только через возврат трафика на старый SQLite-backed stack.
Триггеры rollback:
- новый gateway не проходит smoke;
- сервисы падают на startup;
- критичный API path broken;
- UI не работает;
- ошибки подключения к PostgreSQL не устраняются быстро;
- event bus / voice path деградирует.
Шаги rollback:
- вернуть
DEV_GATEWAY_PUBLICнаDEV_GATEWAY_OLD; - убедиться, что старый SQLite stack всё ещё жив;
- выполнить быстрый smoke на старом stack;
- запретить новый трафик на PostgreSQL-backed stack;
- собрать логи с нового 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
После этого:
- переключить dev gateway/public route на новый stack;
- прогнать smoke ещё раз уже через публичный dev URL;
- оставить старый SQLite stack как rollback target.