Step 8
Step 8 — Change schemas with expand/contract and idempotent backfills
0 views
Step 8 — Change schemas with expand/contract and idempotent backfills
Production tables cannot be treated like an empty local database. Add a compatible shape while old code still runs, backfill in small batches, verify, and only then remove the old contract.
compatible column/index → deploy readers and writers → small backfill
→ count/NULL/sample checks → switch reads → clean up old contract
Compose databases use admin SQL as the SSOT with idempotent CREATE IF NOT EXISTS corrections. A managed external database owns its migration history, so applied migrations are not rewritten. Startup schema init and ORM synchronize would violate that boundary.
Backfills have a batch size, commit interval, and restart point. Running one row twice must converge to the same result. A failed transaction must roll back and the next run must be safe. Dropping a database or recreating a production volume is not recovery evidence.
An admin command that combines DDL and seeding also needs a concurrency boundary. An all-content command acquires a PostgreSQL advisory lock first; if another console replica is already running, it returns 409 INIT_IN_PROGRESS quickly. Do not rely only on a disabled UI button—protect the server and database session boundary too.