Files
spring-boot-demo/db-migrations-expand-contract/docs/10-what-happens-if-you-drop-too-soon.md
T
asmhatreandClaude Sonnet 5 e478eafda3 Add db-migrations-expand-contract: zero-downtime schema migrations proven with a real 4-deploy rolling run
Companion code for Zero-Downtime Database Migrations: Expand-Contract in Practice
with Spring Boot: a full expand/migrate-writes/migrate-reads/contract sequence run
as an actual rolling deploy across two live replicas, with a load generator sending
continuous HTTP traffic through all four deploys (99.98% success, every residual
error traced to a root cause rather than left unexplained). Findings include a real
NOT NULL constraint trap in the expand migration, a backfill-window bug in the read
switch, H2's AUTO_SERVER=TRUE single-point-of-failure behavior under a rolling
restart, the drain-before-SIGTERM fix needed to close a health-check gap during
graceful shutdown, and H2 silently discarding a concurrently committed INSERT during
an ALTER TABLE ADD/DROP COLUMN rebuild - confirmed, by primary source, to be an
H2-specific behavior rather than a property of the technique itself.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019Fb7vW8vLyLKngBc4R3huA
2026-09-16 19:22:48 +00:00

43 lines
2.5 KiB
Markdown

# 10. What happens if you drop too soon
[← 9. The contract migration](09-the-contract-migration.md) · [Next: 11. The load generator →](11-the-load-generator.md)
The second half of
[`ContractSafetyTest`](https://ankurm.com/git.app/asmhatre/spring-boot-demo/src/branch/main/db-migrations-expand-contract/src/test/java/com/ankurm/expandcontract/ContractSafetyTest.java)
runs Deploy 4b's migration first, and only then starts a Stage 1 instance against the
result — standing in for a canary that never got promoted, a rollback that didn't
fully take, or simply running the drop before confirming the fleet:
```
-- What a lingering Stage 1 instance sees if the drop runs before it is retired --
Stage 1 create() after V3 dropped "email": org.springframework.jdbc.BadSqlGrammarException
message: PreparedStatementCallback; bad SQL grammar [INSERT INTO customers(name, email) VALUES (?, ?)]
root cause: org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "EMAIL" not found; SQL statement:
INSERT INTO customers(name, email) VALUES (?, ?) [42122-240]
```
Full transcript:
[`docs/output/10-drop-too-soon.txt`](https://ankurm.com/git.app/asmhatre/spring-boot-demo/src/branch/main/db-migrations-expand-contract/docs/output/10-drop-too-soon.txt).
This is the correct outcome, not a bug to work around. A Stage 1 instance still
running after the drop is itself the actual mistake — a deploy that didn't finish, or
a rollback nobody noticed failed — and the database telling it loudly and immediately
that `email` doesn't exist is far better than the alternative of silently accepting
partial writes or, worse, dropping rows. Expand-contract's safety comes from **when**
you're allowed to run Deploy 4b (only after confirming 100% Stage 4), not from Deploy
4b itself being forgiving of running early.
In a real deploy pipeline, this is the argument for gating Deploy 4b on an explicit
health/version check across the fleet — every instance's `/actuator/info` or
equivalent reporting Stage 4 — rather than a fixed timer. "Deploy 2 usually finishes
rolling out in three minutes" is not the same guarantee as "every replica confirmed
Stage 4", and the difference between them is exactly the window this chapter's test
is exploiting.
## Going deeper
- [Chapter 15](15-production-checklist.md) turns this into an actual gate: what to
check, and where, before running a contract migration in a real pipeline.
[← 9. The contract migration](09-the-contract-migration.md) · [Next: 11. The load generator →](11-the-load-generator.md)