Skip to content

Serialize startup database migrations#13

Merged
kasnder merged 1 commit into
mainfrom
agent/serialize-startup-migrations
Jul 13, 2026
Merged

Serialize startup database migrations#13
kasnder merged 1 commit into
mainfrom
agent/serialize-startup-migrations

Conversation

@kasnder

@kasnder kasnder commented Jul 13, 2026

Copy link
Copy Markdown
Member

Summary

  • acquire a database-scoped PostgreSQL advisory lock before creating schema_migrations, discovering SQL files, or reading migration history
  • hold the lock across every migration transaction, then explicitly release it and close the dedicated database client through finally cleanup
  • log the wait, acquisition latency, release start, and successful release so startup contention is visible
  • extract a testable migration runner and add mocked-client coverage for ordering, rollback, unlock, and client cleanup

Root cause

Production startup runs the migration script automatically. Concurrent instances could each create/read schema_migrations and snapshot the same unapplied files before either instance recorded its work. The existing per-file transactions protected individual statements but did not serialize migration discovery or application across processes.

Impact

Concurrent app starts now wait on one stable advisory-lock key within the target database. After the previous runner releases the lock, the next runner creates/checks the migration table and discovers migration state afresh, so already-applied files are skipped rather than applied twice. Session cleanup also releases the lock automatically if the connection fails while explicit unlock is attempted on normal script failure paths.

Validation

  • node --test test/migrate.test.js — 5/5 passed
  • npm test — 27/27 passed
  • node --check scripts/migrate.js
  • git diff --check

The focused tests use a mocked PostgreSQL client and temporary migration directories; they do not require a production database.

@kasnder

kasnder commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

Review complete. The advisory-lock scope and cleanup paths look correct, including migration discovery/history reads being inside the session lock. No correctness fix needed.

One operational follow-up: pg_advisory_lock can wait indefinitely if a holder session hangs. Consider a bounded pg_try_advisory_lock retry or session lock timeout so deployments fail clearly rather than hanging forever. A short comment documenting that the fixed lock-key tuple is an application namespace would also help if this database is ever shared.

@kasnder
kasnder marked this pull request as ready for review July 13, 2026 14:59
@kasnder
kasnder merged commit d53ed01 into main Jul 13, 2026
2 checks passed
@kasnder
kasnder deleted the agent/serialize-startup-migrations branch July 13, 2026 14:59
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.

1 participant