Skip to content

Flyway: single-pass CREATE INDEX CONCURRENTLY support (pin 13.4.0 + session-level lock + auto-repair) - #438

Merged
Szer merged 5 commits into
mainfrom
flyway-cic-single-pass
Aug 28, 2026
Merged

Szer merged 5 commits into
mainfrom
flyway-cic-single-pass

Conversation

@Szer

@Szer Szer commented Aug 28, 2026 •

Copy link
Copy Markdown
Owner

Root cause

Since Flyway 9.1.2 (commit 022a646), migrate holds a transactional advisory lock across its own DB session (visible as a second idle in transaction session) for the duration of the run. That lock was added for PgBouncer transaction-pooling compatibility. It also means any CREATE INDEX CONCURRENTLY migration Flyway runs waits forever on Flyway's own lock — CIC can never commit inside the same transaction Flyway is holding.

Our Azure Postgres is Burstable tier, where PgBouncer can't be enabled, so the transactional-lock behavior buys us nothing and only breaks CIC.

What changed

  • Pin flyway/flyway to 13.4.0 everywhere (was unpinned :latest, which drifted 12.8.1→13.4.0 within 6 days): .github/workflows/_bot-deploy.yml, .github/workflows/alita-real-test.yml, .github/workflows/coupon-real-test.yml, src/coupon-hub-bot/docker-compose.dev.yml, src/alita-bot/docker-compose.dev.yml, tests/BotTestInfra/ContainerHelpers.fs.

  • Add -postgresql.transactional.lock=false to every migrate invocation in those same places, switching Flyway's cross-run coordination lock to a session-level advisory lock (still serializes concurrent runs, releases on connection death — both proven in a container harness). Regular migration scripts are unaffected — they still run inside their own transaction and roll back atomically.

  • Add an unconditional flyway repair immediately before migrate in the prod deploy workflow (_bot-deploy.yml). repair is a proven no-op when nothing failed (checksum-safe), and is what clears the success=false history row a failed CIC migration leaves behind — without it, every later deploy is blocked forever. Not added to the dev composes / Testcontainers fixture (ContainerHelpers.fs) — doing so there would need real service-ordering restructuring, not a small change, and prod is the hard requirement.

  • Document migration-authoring rules for CIC in AGENTS.md (new subsection under "Database"): author CIC migrations idempotently in the normal versioned dir (no .sql.conf); if a CIC migration Vn fails on a data problem, the fix migration's version must sit strictly between the last-applied version and Vn (e.g. V(n-1).1), never above Vn — a higher version never runs before Vn's identical retry, so it fails forever; unconditional repair means editing an already-applied migration silently realigns its checksum instead of failing validation.

  • Add a new PR-time check (migration-immutability.yml / scripts/check-migration-immutability.sh) that fails on any edit/delete/rename of an already-existing migration file (across all three bots' migrations dirs) — unconditional flyway repair silently realigns checksums of edited applied migrations instead of failing validation, so the no-edits invariant now has to be enforced at PR time.

Test plan

  • dotnet build — green, 0 warnings/errors
  • dotnet test tests/MultiPodTests -c Release — 15/15 passed (1m40s); this suite's fixture (BotContainerBase/MultiPodContainerBase) exercises ContainerHelpers.fs's createFlywayContainer, so it proves the pinned 13.4.0 image + -postgresql.transactional.lock=false flag work end-to-end locally (podman-backed Testcontainers)
  • actionlint on the three touched workflow files — clean
  • Local sanity tests of scripts/check-migration-immutability.sh against a scratch worktree (not this branch): edit-existing → detected (M), delete-existing → detected (D), rename-existing → detected (R), add-then-edit-in-same-PR → passes
  • actionlint on the new workflow file — clean
  • CI (build/test workflows, comment-lint) — to be watched after opening this PR

Closes #407

🤖 Generated with Claude Code

https://claude.ai/code/session_011Ksbj9x1jrixy8qhSE5H46

Szer and others added 5 commits August 28, 2026 12:21
…ession-level lock + auto-repair)

Pin flyway/flyway to 13.4.0 everywhere, add -postgresql.transactional.lock=false
to every migrate invocation (Flyway's default transactional advisory lock since
9.1.2 deadlocks against CIC), and run repair unconditionally before migrate in
prod deploy to auto-clear a failed CIC migration's success=false history row.
Documents the versioning trap for CIC data-fix migrations in AGENTS.md.

Closes #407

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Ksbj9x1jrixy8qhSE5H46
Unconditional flyway repair (#438) silently realigns checksums of edited
applied migrations instead of failing validation, so the no-edits invariant
must now be enforced at PR time: fail on any edit/delete/rename of an
existing migration file, diffed against the merge-base with the target
branch, across all three bots' migrations dirs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Ksbj9x1jrixy8qhSE5H46
Edits, deletes, and renames an existing migration in each bot's dir to
verify migration-immutability.yml catches all three cases in real CI.
This commit is reverted by the next one before merge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Ksbj9x1jrixy8qhSE5H46
…erted)"

This reverts commit ac3f052.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Ksbj9x1jrixy8qhSE5H46
A path-filtered required check never runs on PRs that don't touch
migrations, blocking merge forever on a check that never reports. Run on
every pull_request instead; the script exits 0 immediately when no
migration files changed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Ksbj9x1jrixy8qhSE5H46
@Szer
Szer merged commit 29b978b into main Aug 28, 2026
8 checks passed
@Szer
Szer deleted the flyway-cic-single-pass branch August 28, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flyway: figure out CREATE INDEX CONCURRENTLY in migrations (per-script transactional-lock)

1 participant