fix: PgLockRegistry uses single shared connection for all advisory locks #172

Merged
ash merged 3 commits from fix/shared-advisory-conn into main 2026-03-02 23:12:16 +00:00
Owner

Fixes #171

One PG connection can hold thousands of advisory locks (session-scoped). Previous impl used one connection per lock, exhausting the pool.

Before: N locks = N connections held permanently
After: N locks = 1 connection

Changes:

  • Single shared connection protected by mutex
  • Refcount tracks held locks
  • Auto-reconnect on stale connection
  • Close() for clean shutdown
Fixes #171 One PG connection can hold thousands of advisory locks (session-scoped). Previous impl used one connection per lock, exhausting the pool. **Before:** N locks = N connections held permanently **After:** N locks = 1 connection Changes: - Single shared connection protected by mutex - Refcount tracks held locks - Auto-reconnect on stale connection - `Close()` for clean shutdown
fix: PgLockRegistry uses single shared connection for all advisory locks
Some checks failed
CI / test-sqlitestore (push) Failing after 3s
CI / test-pgstore (push) Failing after 3s
CI / test-nats (push) Failing after 5s
CI / test-integration (push) Failing after 4s
CI / benchmarks (push) Failing after 4s
CI / test-codec-otelkit (push) Successful in 12s
CI / test-sqlitestore (pull_request) Failing after 5s
CI / test-pgstore (pull_request) Failing after 4s
CI / test-nats (pull_request) Failing after 6s
CI / test-integration (pull_request) Failing after 4s
CI / benchmarks (pull_request) Failing after 4s
CI / test-codec-otelkit (pull_request) Successful in 13s
CI / test-core (push) Failing after 1m13s
CI / test-core (pull_request) Failing after 1m13s
441a9040d9
One PG connection can hold thousands of advisory locks (session-scoped).
Previous impl used one connection per lock, exhausting the pool when many
subscriptions/automations were configured.

- Single shared connection protected by mutex
- Refcount tracks held locks, connection released when last lock released
- Auto-reconnect on stale connection (PG restart)
- Close() for clean shutdown

Closes #171
fix: reject reentrant advisory lock acquisition
Some checks failed
CI / test-sqlitestore (push) Failing after 4s
CI / test-pgstore (push) Failing after 4s
CI / test-nats (push) Failing after 6s
CI / test-integration (push) Failing after 5s
CI / benchmarks (push) Failing after 4s
CI / test-codec-otelkit (push) Successful in 14s
CI / test-sqlitestore (pull_request) Failing after 5s
CI / test-pgstore (pull_request) Failing after 5s
CI / test-nats (pull_request) Failing after 7s
CI / test-integration (pull_request) Failing after 5s
CI / test-codec-otelkit (pull_request) Successful in 15s
CI / benchmarks (pull_request) Failing after 5s
CI / test-core (pull_request) Has been cancelled
CI / test-core (push) Has been cancelled
f98c6a4e14
Advisory locks are reentrant within the same PG session — same connection
acquiring the same lock silently succeeds. With shared connection, this means
TryAcquire/Acquire on an already-held lock would incorrectly succeed.

Add app-level guard: check held map before calling PG. Return error (Acquire)
or false (TryAcquire) if lock already held by this registry.
test: update lock tests for shared connection, add reentrancy and multi-lock tests
Some checks failed
CI / test-sqlitestore (push) Failing after 4s
CI / test-pgstore (push) Failing after 5s
CI / test-nats (push) Failing after 8s
CI / test-integration (push) Failing after 5s
CI / benchmarks (push) Failing after 4s
CI / test-codec-otelkit (push) Successful in 15s
CI / test-sqlitestore (pull_request) Failing after 5s
CI / test-pgstore (pull_request) Failing after 4s
CI / test-nats (pull_request) Failing after 6s
CI / test-integration (pull_request) Failing after 5s
CI / test-codec-otelkit (pull_request) Successful in 12s
CI / benchmarks (pull_request) Failing after 4s
CI / test-core (pull_request) Failing after 1m13s
CI / test-core (push) Failing after 1m40s
289c46e297
- SingleWriter: each goroutine gets own registry (simulates separate nodes)
- TryAcquire: uses two registries for cross-session contention
- New: ReentrantRejected — verifies same-registry double-acquire fails
- New: MultipleLocks_SharedConnection — 20 locks on 1 connection
ash merged commit 088cb853ee into main 2026-03-02 23:12:16 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ash/eskit!172
No description provided.