@@ -934,6 +934,18 @@ func (p *pool) checkInNoEvent(conn *connection) error {
934934 go func () {
935935 _ = p .closeConnection (conn )
936936 }()
937+
938+ // Since we are removing the connection, we should try to queue another
939+ // in good faith in case the current idle wait queue is being awaited
940+ // in a checkOut() call.
941+ p .createConnectionsCond .L .Lock ()
942+ w := p .newConnWait .popFront ()
943+ p .createConnectionsCond .L .Unlock ()
944+
945+ if w != nil {
946+ p .queueForNewConn (context .Background (), w )
947+ }
948+
937949 return nil
938950 }
939951
@@ -1128,15 +1140,29 @@ func (p *pool) getOrQueueForIdleConn(w *wantConn) bool {
11281140 return false
11291141}
11301142
1143+ // queueForNewConn enqueues a checkout request and signals the
1144+ // connection-creation state machine. It does NOT initiate dialing directly,
1145+ // but places the wantConn into the pending queue and wakes a background worker
1146+ // using sync.Cond. That worker will then dequeue in FIFO order and perform the
1147+ // actual dial under it's own synchronization, preserving order.
11311148func (p * pool ) queueForNewConn (ctx context.Context , w * wantConn ) {
11321149 p .createConnectionsCond .L .Lock ()
11331150 defer p .createConnectionsCond .L .Unlock ()
11341151
1152+ // Remove any wantConn entries at the front that are no longer waiting. This
1153+ // keeps the queue clean and avoids delivering to canceled requests.
11351154 p .newConnWait .cleanFront ()
1155+
1156+ // Enqueu this wantConn for allocation of a new connection.
11361157 p .newConnWait .pushBack (w )
1158+
1159+ // Signale on goroutine waiting in waitForNewConn that pool state changed and
1160+ // new wantConn is available. That goroutine will then dequeue under lock.
11371161 p .createConnectionsCond .Signal ()
11381162
1139- // Try to spawn without blocking the caller.
1163+ // Spawn a background worker to service the queue without blocking callers. We
1164+ // do NOT pass "w" here because the worker must re-acquite the queue lock and
1165+ // pick the next available wantConn in FIFO order via waitForNewConn.
11401166 go p .spawnConnectionIfNeeded (ctx )
11411167}
11421168
@@ -1529,6 +1555,11 @@ func (p *pool) waitForNewConn(ctx context.Context) (*wantConn, *connection, bool
15291555// spawnConnectionIfNeeded takes on waiting waitConn (if any) and starts its
15301556// connection creation subject to the semaphore limit.
15311557func (p * pool ) spawnConnectionIfNeeded (ctx context.Context ) {
1558+ if ! p .hasSpace () {
1559+ // If the pool is full, we can't spawn a new connection.
1560+ return
1561+ }
1562+
15321563 // Block until we're allowed to start another connection.
15331564 p .connectionSem <- struct {}{}
15341565
0 commit comments