📝 Description
During recovery from a temporary PostgreSQL outage, pgxpool.Pool can experience a race condition under heavy contention. When the database becomes reachable again, multiple goroutines blocked on Acquire() simultaneously attempt to establish new connections.
Because the pool does not immediately account for "in-flight" or pending connection attempts, multiple goroutines independently observe that the current pool size is below MaxConns. Consequently, they all initiate physical connection establishment (dialing and handshaking) concurrently. This leads to:
- A temporary breach of the configured
MaxConns limit.
- Connection storms that can exhaust PostgreSQL's
max_connections limit.
- Increased CPU and authentication load on both the client and the database during recovery.
The pool must track pending connection attempts and ensure that len(active_connections) + pending_connections never exceeds MaxConns.
🎯 Acceptance Criteria
🛠️ Technical Specifications & Context
- Target Package:
github.com/jackc/pgx/v5/pgxpool (or the corresponding version in colmev080/pgx).
- Key Files:
- Implementation Details:
- Locate the connection creation logic within
pgxpool.Pool.Acquire() or the internal helper that handles pool expansion (often involving a resource pool implementation like github.com/jackc/puddle).
- If
puddle is used, ensure that the reservation of a slot happens before the physical connection is dialed. In puddle, this is typically managed by acquiring a placeholder or incrementing a counter before performing the slow I/O operation.
- If custom tracking is required, introduce a thread-safe counter (e.g., using
sync/atomic or guarded by the pool's internal mutex) to track pendingConnections.
- Before dialing a new connection:
- Check if
activeConnections + pendingConnections < MaxConns.
- If yes, increment
pendingConnections and proceed to dial.
- If no, block the goroutine until a connection is returned or a pending attempt fails.
- Ensure a
defer block or robust try-catch equivalent handles decrementing pendingConnections if the connection creation returns an error.
🧪 Verification & Testing
- Unit/Integration Test:
- Create a test case in
pgxpool/pool_test.go that mocks or simulates a slow connection establishment (e.g., using a custom BeforeConnect hook or a dialer that sleeps for 100ms).
- Configure the pool with a small
MaxConns (e.g., 5).
- Concurrently spawn a large number of goroutines (e.g., 50) calling
Acquire().
- Verify that:
- The total number of concurrent dial attempts never exceeds 5.
- The total number of successfully established connections never exceeds 5.
- If some dial attempts are forced to fail, the pool eventually recovers and allows new attempts up to the limit of 5.

This repo is using Opire - what does it mean? 👇
💵 Everyone can add rewards for this issue commenting /reward 100 (replace 100 with the amount).
🕵️♂️ If someone starts working on this issue to earn the rewards, they can comment /try to let everyone know!
🙌 And when they open the PR, they can comment /claim #3 either in the PR description or in a PR's comment.
🪙 Also, everyone can tip any user commenting /tip 20 @colmev080 (replace 20 with the amount, and @colmev080 with the user to tip).
📖 If you want to learn more, check out our documentation.
📝 Description
During recovery from a temporary PostgreSQL outage,
pgxpool.Poolcan experience a race condition under heavy contention. When the database becomes reachable again, multiple goroutines blocked onAcquire()simultaneously attempt to establish new connections.Because the pool does not immediately account for "in-flight" or pending connection attempts, multiple goroutines independently observe that the current pool size is below
MaxConns. Consequently, they all initiate physical connection establishment (dialing and handshaking) concurrently. This leads to:MaxConnslimit.max_connectionslimit.The pool must track pending connection attempts and ensure that
len(active_connections) + pending_connectionsnever exceedsMaxConns.🎯 Acceptance Criteria
MaxConnsconfiguration limit, even under high concurrency and during recovery from database outages.len(established_connections) + pending_connections >= MaxConns, subsequentAcquire()calls must block and wait for an available connection or a slot to open, rather than initiating new connection attempts.🛠️ Technical Specifications & Context
github.com/jackc/pgx/v5/pgxpool(or the corresponding version incolmev080/pgx).pgxpool/pool.gopgxpool.Pool.Acquire()or the internal helper that handles pool expansion (often involving a resource pool implementation likegithub.com/jackc/puddle).puddleis used, ensure that the reservation of a slot happens before the physical connection is dialed. Inpuddle, this is typically managed by acquiring a placeholder or incrementing a counter before performing the slow I/O operation.sync/atomicor guarded by the pool's internal mutex) to trackpendingConnections.activeConnections + pendingConnections < MaxConns.pendingConnectionsand proceed to dial.deferblock or robusttry-catchequivalent handles decrementingpendingConnectionsif the connection creation returns an error.🧪 Verification & Testing
pgxpool/pool_test.gothat mocks or simulates a slow connection establishment (e.g., using a customBeforeConnecthook or a dialer that sleeps for 100ms).MaxConns(e.g., 5).Acquire().This repo is using Opire - what does it mean? 👇
💵 Everyone can add rewards for this issue commenting
/reward 100(replace100with the amount).🕵️♂️ If someone starts working on this issue to earn the rewards, they can comment
/tryto let everyone know!🙌 And when they open the PR, they can comment
/claim #3either in the PR description or in a PR's comment.🪙 Also, everyone can tip any user commenting
/tip 20 @colmev080(replace20with the amount, and@colmev080with the user to tip).📖 If you want to learn more, check out our documentation.