Skip to content

Commit e0793b8

Browse files
committed
fix(db): gate pid session guard to direct migration connections (pooler pids legitimately vary)
1 parent 85a47d0 commit e0793b8

1 file changed

Lines changed: 18 additions & 6 deletions

File tree

packages/db/scripts/migrate.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,16 @@ if (!url) {
6565
process.exit(1)
6666
}
6767

68+
/**
69+
* The backend-pid session guard below is only sound on a DIRECT connection:
70+
* through a transaction-pooling PgBouncer, consecutive statements can
71+
* legitimately run on different server backends, so a pid change does not mean
72+
* the session was lost and the guard would false-positive on every run.
73+
* MIGRATION_DATABASE_URL is by contract the direct DSN; when falling back to
74+
* DATABASE_URL (which may be pooled), the guard is skipped.
75+
*/
76+
const hasDirectMigrationUrl = Boolean(process.env.MIGRATION_DATABASE_URL)
77+
6878
/**
6979
* `max_lifetime: null` is load-bearing: postgres-js defaults to recycling the
7080
* connection after a randomized 30–60 minutes, and a transparent reconnect
@@ -178,12 +188,14 @@ async function acquireMigrationLock(): Promise<void> {
178188
*/
179189
async function runMigrationsWithRetry(): Promise<void> {
180190
for (let attempt = 1; ; attempt++) {
181-
const [{ pid }] = await client`SELECT pg_backend_pid() AS pid`
182-
if (pid !== lockSessionPid) {
183-
throw new Error(
184-
`Database session changed mid-run (backend pid ${lockSessionPid} -> ${pid}); ` +
185-
'the migration advisory lock was lost. Aborting so a fresh runner can retry safely.'
186-
)
191+
if (hasDirectMigrationUrl) {
192+
const [{ pid }] = await client`SELECT pg_backend_pid() AS pid`
193+
if (pid !== lockSessionPid) {
194+
throw new Error(
195+
`Database session changed mid-run (backend pid ${lockSessionPid} -> ${pid}); ` +
196+
'the migration advisory lock was lost. Aborting so a fresh runner can retry safely.'
197+
)
198+
}
187199
}
188200
await client.unsafe('SET statement_timeout = 0')
189201
await client.unsafe(`SET lock_timeout = '${DDL_LOCK_TIMEOUT}'`)

0 commit comments

Comments
 (0)