From 8cc64737362f67af0bf31cedd9f1dc44afea070e Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Tue, 10 Mar 2026 08:51:46 -0700 Subject: [PATCH] fix: increase migration lock timeout to prevent flaky parallel test (#22910) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem `TestMigrate/Parallel` flakes with: ``` timeout: can't acquire database lock ``` ## Root Cause The test runs two concurrent `migrations.Up(db)` calls on the same database. golang-migrate wraps every `Lock()` call with a [15-second timeout](https://github.com/golang-migrate/migrate/blob/v4.19.0/migrate.go#L29) (`DefaultLockTimeout`). Our `pgTxnDriver.Lock()` uses `pg_advisory_xact_lock`, which blocks until the lock is available. With 430+ migrations, the first caller can hold the lock well beyond 15s (the failing test ran for 25.88s), causing the second caller to hit the timeout. ## Fix Set `m.LockTimeout = 2 * time.Minute` after creating the `migrate.Migrate` instance in `setup()`. Since `pg_advisory_xact_lock` releases automatically when the transaction commits, there's no risk of a stuck lock — we just need to wait long enough for a concurrent migration to finish. --- coderd/database/migrations/migrate.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/coderd/database/migrations/migrate.go b/coderd/database/migrations/migrate.go index c6c1b5740f..50a931c902 100644 --- a/coderd/database/migrations/migrate.go +++ b/coderd/database/migrations/migrate.go @@ -12,6 +12,7 @@ import ( "sort" "strings" "sync" + "time" "github.com/golang-migrate/migrate/v4" "github.com/golang-migrate/migrate/v4/source" @@ -101,6 +102,13 @@ func setup(db *sql.DB, migs fs.FS) (source.Driver, *migrate.Migrate, error) { return nil, nil, xerrors.Errorf("new migrate instance: %w", err) } + // The default LockTimeout of 15s is too short for concurrent migrations, + // especially when the number of migrations is large. Since we use + // pg_advisory_xact_lock which releases automatically when the transaction + // ends, we just need to wait long enough for any concurrent migration to + // finish. + m.LockTimeout = 2 * time.Minute + return sourceDriver, m, nil }