db-migrations-expand-contract: add a dedicated reproduction for the DDL-collision exception
While writing the article, chapter 14's first failure mode (a concurrent statement seeing "Table CUSTOMERS not found" while DROP COLUMN runs) was described from the live load-generator run but had no dedicated, committed reproduction of its own - CustomerService's own retry would silently absorb it if triggered through the service layer. DdlCollisionExceptionTest reproduces it directly at the raw JDBC level, and the chapter and README now link to its captured transcript. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019Fb7vW8vLyLKngBc4R3huA
This commit is contained in:
@@ -16,17 +16,31 @@ the handful of errors it reported.
|
||||
|
||||
## Failure mode 1: a statement that collides with the DDL, and says so
|
||||
|
||||
While `V3__drop_email_column.sql` runs, a concurrent, otherwise-correct `INSERT` or
|
||||
`UPDATE` can briefly see:
|
||||
While `V3__drop_email_column.sql` runs, a concurrent, otherwise-correct query can
|
||||
briefly see the table disappear out from under it.
|
||||
[`DdlCollisionExceptionTest`](https://ankurm.com/git.app/asmhatre/spring-boot-demo/src/branch/main/db-migrations-expand-contract/src/test/java/com/ankurm/expandcontract/DdlCollisionExceptionTest.java)
|
||||
reproduces this directly, at the raw JDBC level — one thread reading the table in a
|
||||
tight loop while `V3` (`DROP COLUMN`) runs concurrently on another connection:
|
||||
|
||||
```
|
||||
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "CUSTOMERS" not found
|
||||
successful reads while DROP COLUMN was in flight: 222
|
||||
reads that collided with the in-flight DROP COLUMN: 1
|
||||
example: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "CUSTOMERS" not found; SQL statement:
|
||||
SELECT COUNT(*) FROM customers [42102-240]
|
||||
```
|
||||
|
||||
This is a real, transient condition captured live, twice, in independent runs of this
|
||||
module's load generator — not a bug in the application's SQL. H2's TCP server
|
||||
appears to make the table briefly unavailable to other sessions while `DROP COLUMN`
|
||||
executes. The fix is a narrowly scoped single retry in
|
||||
Full transcript:
|
||||
[`docs/output/14-ddl-collision-exception.txt`](https://ankurm.com/git.app/asmhatre/spring-boot-demo/src/branch/main/db-migrations-expand-contract/docs/output/14-ddl-collision-exception.txt).
|
||||
This test bypasses `CustomerService` deliberately — its own retry would silently
|
||||
absorb the very exception this test exists to show — and, like
|
||||
`DdlSilentDataLossTest` below, repeats the race until it reproduces, since exactly
|
||||
when it fires is OS thread scheduling, not application logic.
|
||||
|
||||
This same condition is what first showed up as `create-http-500` / `update-http-500`
|
||||
errors in this module's own live load-generator run, twice, in independent runs —
|
||||
not a bug in the application's SQL. H2's TCP server appears to make the table
|
||||
briefly unavailable to other sessions while `DROP COLUMN` executes. The fix is a
|
||||
narrowly scoped single retry in
|
||||
[`CustomerService.withRetryForConcurrentDdl`](https://ankurm.com/git.app/asmhatre/spring-boot-demo/src/branch/main/db-migrations-expand-contract/src/main/java/com/ankurm/expandcontract/customer/CustomerService.java):
|
||||
|
||||
```java
|
||||
|
||||
Reference in New Issue
Block a user