diff options
| -rw-r--r-- | CHANGELOG.md | 6 | ||||
| -rw-r--r-- | pgruntime/behavior.go | 17 |
2 files changed, 22 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 77b3972..e7bfdf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ SPDX-FileCopyrightText: 2026 Stefan Majewsky <majewsky@gmx.net> SPDX-License-Identifier: Apache-2.0 --> +# v1.13.2 (TBD) + +Changes: + +- pgruntime: Add transaction locking to protect against concurrent migrations. + # v1.13.1 (2026-08-05) Changes: diff --git a/pgruntime/behavior.go b/pgruntime/behavior.go index 3ffff1e..03ff338 100644 --- a/pgruntime/behavior.go +++ b/pgruntime/behavior.go @@ -110,7 +110,22 @@ func applyMigrations(ctx context.Context, db gsql.ConnectionHandle, migrations m // apply migrations for _, version := range pendingVersions { err := db.GSQLTransact(ctx, func(tx gsql.Handle) error { - _, err := execQuery(ctx, db, migrations[version], nil) + // ensure that nobody else is migrating until we are done + var actualVersion int64 + err := queryRow(ctx, db, `SELECT version FROM schema_migrations FOR UPDATE`, nil, []any{&actualVersion}) + if err != nil { + return fmt.Errorf("could not obtain lock for schema migration: %w", err) + } + + // ensure that nobody else migrated just before we started our transaction block + if version <= actualVersion { + return fmt.Errorf("tried to perform migration to version %d, but schema is already at version %d (multiple migrations might be running concurrently)", + version, actualVersion, + ) + } + + // perform the next migration + _, err = execQuery(ctx, db, migrations[version], nil) if err != nil { return fmt.Errorf("could not execute schema migration: %w", err) } |
