@@ -142,25 +142,43 @@ func warmupSelections(rounds, skip int) int {
142142
143143// drainWarmup pumps enough requests through the transport to complete warmup
144144// on all connections, allowing deferred cap enforcement to fire.
145- func drainWarmup (transport * opensearchtransport.Client ) {
145+ //
146+ // The context bounds total execution time. When the pool has 0 live connections,
147+ // every Perform falls through to seed-fallback (a full TLS round-trip). Without
148+ // a context check, the fixed iteration count can consume the entire retry budget
149+ // of the caller (e.g., discoverWithStandby's 30s timeout).
150+ //
151+ // Consecutive errors (maxConsecErrors) trigger an early exit: the pool is empty
152+ // or unhealthy and further requests would just burn time on seed fallback.
153+ func drainWarmup (ctx context.Context , transport * opensearchtransport.Client ) {
146154 const (
147155 nodeCount = 3
148156 warmupRounds = 4
149157 warmupSkipMultiple = 2
158+ maxConsecErrors = 5
150159 )
151160 warmupSkip := warmupRounds * warmupSkipMultiple
152161 selectionsPerConn := warmupSelections (warmupRounds , warmupSkip )
153162 drainRequests := selectionsPerConn * nodeCount * 3 / 2
154163
164+ consecErrors := 0
155165 for range drainRequests {
156- req , err := http .NewRequest (http .MethodGet , "/" , nil )
166+ if ctx .Err () != nil {
167+ return
168+ }
169+ req , err := http .NewRequestWithContext (ctx , http .MethodGet , "/" , nil )
157170 if err != nil {
158171 break
159172 }
160173 resp , err := transport .Perform (req )
161174 if err != nil {
175+ consecErrors ++
176+ if consecErrors >= maxConsecErrors {
177+ return
178+ }
162179 continue
163180 }
181+ consecErrors = 0
164182 resp .Body .Close ()
165183 }
166184}
@@ -206,7 +224,7 @@ func discoverWithStandby(t *testing.T, transport *opensearchtransport.Client) op
206224
207225 // Pump requests to drain warmup. Cap enforcement is deferred until
208226 // connections finish warming (via Next()'s deferred path).
209- drainWarmup (transport )
227+ drainWarmup (ctx , transport )
210228
211229 m , err = transport .Metrics ()
212230 require .NoError (t , err )
@@ -371,7 +389,7 @@ func TestStandbyRotation(t *testing.T) {
371389 time .Sleep (discoveryPause )
372390 continue
373391 }
374- drainWarmup (transport )
392+ drainWarmup (t . Context (), transport )
375393
376394 promotions := obs .promotionCount ()
377395 demotions := obs .demotionCount ()
@@ -474,7 +492,7 @@ func TestStandbyRotation(t *testing.T) {
474492 time .Sleep (discoveryPause )
475493 continue
476494 }
477- drainWarmup (transport )
495+ drainWarmup (t . Context (), transport )
478496
479497 promotions := obs .promotionCount ()
480498 t .Logf ("Cycle %d attempt %d: promotions=%d (prev=%d)" ,
0 commit comments