feat(namedlock): add PostgreSQL advisory-lock implementation - #938
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
🤖 Adversarial correctness review, requested by Armand and performed by his agent. Reviewed at head Verdict: one fix-before-merge finding — a lock-leak window on the pooled-connection acquire-error path — plus a PR-body correction. The core design (transaction-local Finding 1 (fix before merge): a failed commit leaves a pooled session holding the advisory lock
The window is realizable, not theoretical: The MySQL locker can't hit this — its single Suggested fix, contained to Finding 2 (PR body): the test claims overstate the diffThe body says the shared integration suite "now runs against both MySQL and PostgreSQL containers, proving behavioral parity (acquire, contention, timeout, release, connection-scoped auto-release)". What's in the diff: the shared suite is still the two MySQL-only tests, the PG coverage is four separate mirrored tests, and no test in either dialect covers connection-scoped auto-release. Worth correcting the body — and a real auto-release test (dedicated Verified solid: the This review was generated by Claude Code (claude-fable-5). |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
aa55d64 to
9aab079
Compare
There was a problem hiding this comment.
Pull request overview
Adds PostgreSQL support to SchemaBot’s session-scoped “named lock” seam by implementing namedlock.Postgres using advisory locks, and introduces embedded PostgreSQL storage-schema DDL plus tests to keep Postgres and MySQL schemas aligned.
Changes:
- Implement
namedlock.Postgreswithpg_try_advisory_lockfor zero-wait and bounded waits via transaction-locallock_timeout. - Add embedded
pkg/schema/postgres/*.sqlstorage schema files and schema parity/lint/integration tests against a real Postgres container. - Extend namedlock integration tests and CI image pre-pulls to include PostgreSQL.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| pkg/testutil/container.go | Generalize container connection string helper comment for non-MySQL DBs. |
| pkg/schema/schema.go | Embed and document PostgresFS alongside MySQLFS. |
| pkg/schema/postgres/webhook_events.sql | PostgreSQL DDL for webhook_events table + indexes. |
| pkg/schema/postgres/tasks.sql | PostgreSQL DDL for tasks table + indexes. |
| pkg/schema/postgres/settings.sql | PostgreSQL DDL for settings table + indexes. |
| pkg/schema/postgres/plans.sql | PostgreSQL DDL for plans table + indexes. |
| pkg/schema/postgres/plan_comments.sql | PostgreSQL DDL for plan_comments table + indexes. |
| pkg/schema/postgres/locks.sql | PostgreSQL DDL for locks table + indexes. |
| pkg/schema/postgres/checks.sql | PostgreSQL DDL for checks table + indexes. |
| pkg/schema/postgres/apply_target_locks.sql | PostgreSQL DDL for apply_target_locks table + indexes. |
| pkg/schema/postgres/apply_operations.sql | PostgreSQL DDL for apply_operations table + indexes. |
| pkg/schema/postgres/apply_logs.sql | PostgreSQL DDL for apply_logs table + indexes. |
| pkg/schema/postgres/apply_control_requests.sql | PostgreSQL DDL for apply_control_requests table + indexes. |
| pkg/schema/postgres/apply_comments.sql | PostgreSQL DDL for apply_comments table + indexes. |
| pkg/schema/postgres/applies.sql | PostgreSQL DDL for applies table + indexes. |
| pkg/schema/postgres_test.go | Unit tests to lint Postgres schema files and enforce parity with MySQL indexes/files. |
| pkg/schema/postgres_integration_test.go | Integration test that executes Postgres DDL and validates column-by-column parity with MySQL schema. |
| pkg/namedlock/postgres.go | New Postgres advisory-lock implementation of namedlock.Locker. |
| pkg/namedlock/postgres_test.go | Unit tests pin advisory-lock key hashing for cross-version stability. |
| pkg/namedlock/postgres_integration_test.go | Integration tests validating Postgres locker semantics (contention, timeout, release). |
| pkg/namedlock/namedlock.go | Update package docs to include Postgres lock semantics. |
| pkg/namedlock/namedlock_integration_test.go | Start a shared Postgres container in TestMain alongside MySQL for integration tests. |
| go.mod | Add pgx driver and testcontainers Postgres module dependencies. |
| go.sum | Dependency lockfile updates for Postgres-related modules. |
| .github/workflows/test.yaml | Pre-pull postgres:16 image in CI to reduce test startup overhead. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Postgres counterpart to the MySQL GET_LOCK locker, prerequisite for the Postgres schema bootstrapper and state store. Bounded waits use a transaction-local lock_timeout so the bound cannot leak into pooled connections; a failed commit after the lock is granted undoes the acquisition so a pooled session can never strand the lock. Names hash to int64 advisory-lock keys via sha256, pinned by test so mixed-version pods keep excluding each other during rolling deploys.
9aab079 to
fc7b375
Compare
|
Review response from Kiran's (@Kiran01bm) AI code review assessment agent Both findings are fixed at the current head (the branch was also rebased past the #936 squash-merge, so the reviewed head
|
Summary
Adds
namedlock.Postgres, the PostgreSQL advisory-lock implementation of thenamedlock.Lockerseam. This is the Postgres counterpart tonamedlock.MySQL(GET_LOCK/RELEASE_LOCK) and a prerequisite for both the Postgres schema bootstrapper and the Postgres state store's injected locker.What
namedlock.Postgresacquires session-level advisory locks (pg_advisory_lock/pg_advisory_unlock) on the pinned connection, matching the connection-lifetime semantics the seam already guarantees.pg_try_advisory_lock(non-blocking, immediate verdict).lock_timeoutviaset_config(..., true)so the timeout cannot leak into pooled connections; SQLSTATE55P03(lock_not_available) maps toacquired=false, err=nil, mirroring MySQL'sGET_LOCK(...) = 0.lock_timeoutleak check as a Postgres-only extra.Why
MySQL named locks (
GET_LOCK) have no direct PostgreSQL equivalent; advisory locks are the idiomatic replacement but differ in shape (int64 keys instead of strings, no per-call wait argument). This change absorbs those differences behind the existingLockerinterface so callers (apply-target lock, pending-drops lock, schema-bootstrap lock) stay dialect-agnostic.Before / after