276 lines
9.6 KiB
Markdown
276 lines
9.6 KiB
Markdown
# 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](/e:/Zhan/.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 зависимости:
|
||
|
||
```powershell
|
||
python -m pip install -r requirements.txt
|
||
```
|
||
|
||
2. Подготовить env-файл:
|
||
- скопировать [\.env.postgres.local.template](/e:/Zhan/.env.postgres.local.template)
|
||
- заполнить `DATABASE_URL`, `APP_TOKEN_SECRET`, интеграционные URL и при необходимости AI/Telegram/WhatsApp переменные
|
||
|
||
3. Запустить DB-only preflight:
|
||
|
||
```powershell
|
||
python scripts\postgres_dev_preflight.py --env-file .env.postgres.local.template
|
||
```
|
||
|
||
4. Убедиться, что mode не legacy:
|
||
|
||
```text
|
||
SCHEMA_MANAGEMENT_MODE=migrations
|
||
```
|
||
|
||
5. Применить миграции в PostgreSQL:
|
||
|
||
```powershell
|
||
python scripts\migrate_core_db.py
|
||
```
|
||
|
||
Ожидается:
|
||
|
||
- миграции применились без ошибок;
|
||
- в PostgreSQL появилась таблица `schema_migrations`;
|
||
- сервисы ещё не стартовали.
|
||
|
||
## Phase 2 - Bring Up Parallel Stack
|
||
|
||
Поднять новый stack параллельно старому.
|
||
|
||
Если запуск локальный:
|
||
|
||
```powershell
|
||
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:
|
||
|
||
```powershell
|
||
python scripts\postgres_dev_preflight.py `
|
||
--env-file .env.postgres.local.template `
|
||
--base-url http://127.0.0.1:8080
|
||
```
|
||
|
||
1. Health:
|
||
|
||
```powershell
|
||
python scripts\live_smoke_gate12.py --base-url http://<DEV_GATEWAY_NEW> --database-url <POSTGRES_DATABASE_URL>
|
||
```
|
||
|
||
2. Focused PostgreSQL smoke:
|
||
|
||
```powershell
|
||
pytest -q tests/test_postgres_readiness.py
|
||
```
|
||
|
||
3. Дополнительно проверить вручную:
|
||
|
||
- `GET /proxy/auth/health`
|
||
- `GET /proxy/interaction/health`
|
||
- `GET /proxy/voice/health`
|
||
- `GET /proxy/ai-voice-runtime/health`
|
||
- открыть `http://<DEV_GATEWAY_NEW>/operator`
|
||
|
||
4. Если в 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:
|
||
|
||
```powershell
|
||
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:
|
||
|
||
```powershell
|
||
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.
|