Summary
In v0.3.0, Observation.CloseContext returns its dedicated pgx connection to the pool even when releasing the session-level advisory lock fails:
err := dbgen.New(o.conn).ReleaseEntitySessionLock(ctx, o.key)
o.conn.Release()
if err != nil {
return fmt.Errorf("release observation lock %s: %w", o.key, err)
}
Because PostgreSQL advisory locks are session-scoped, an unlock failure means the physical session may still own the lock. Returning that connection to pgxpool can preserve the lock indefinitely and allow a later borrower to inherit the locked session.
The fetch handlers also invoke CloseContext through deferred calls whose errors are intentionally ignored, so the cleanup failure is not surfaced operationally.
Reproduction
- Begin an observation so that a dedicated connection owns a session-level advisory lock.
- Cause
ReleaseEntitySessionLock to fail or exceed the five-second cleanup timeout.
- Call
CloseContext and observe that it returns an error after calling conn.Release().
- Inspect
pg_locks or reacquire the same pooled session and observe that the advisory lock can remain owned.
Expected behavior
A connection whose session lock could not be released must not be returned to the pool. The physical connection should be discarded or closed, and the cleanup failure should be observable through logging, tracing, or metrics.
Actual behavior
The connection is unconditionally returned to the pool before the unlock error is handled, and callers discard the returned error.
Possible fix
- On unlock failure, destroy or close the physical connection instead of releasing it back to the pool.
- Return the connection normally only after a confirmed successful unlock.
- Surface deferred cleanup failures through a bounded log, trace event, or metric.
- Add a regression test that forces unlock failure and verifies that no reusable pooled session retains the advisory lock.
Summary
In v0.3.0,
Observation.CloseContextreturns its dedicated pgx connection to the pool even when releasing the session-level advisory lock fails:Because PostgreSQL advisory locks are session-scoped, an unlock failure means the physical session may still own the lock. Returning that connection to
pgxpoolcan preserve the lock indefinitely and allow a later borrower to inherit the locked session.The fetch handlers also invoke
CloseContextthrough deferred calls whose errors are intentionally ignored, so the cleanup failure is not surfaced operationally.Reproduction
ReleaseEntitySessionLockto fail or exceed the five-second cleanup timeout.CloseContextand observe that it returns an error after callingconn.Release().pg_locksor reacquire the same pooled session and observe that the advisory lock can remain owned.Expected behavior
A connection whose session lock could not be released must not be returned to the pool. The physical connection should be discarded or closed, and the cleanup failure should be observable through logging, tracing, or metrics.
Actual behavior
The connection is unconditionally returned to the pool before the unlock error is handled, and callers discard the returned error.
Possible fix