@@ -250,6 +250,25 @@ func (b *Backoff) Step() time.Duration {
250
250
return duration
251
251
}
252
252
253
+ // contextForChannel derives a child context from a parent channel.
254
+ //
255
+ // The derived context's Done channel is closed when the returned cancel function
256
+ // is called or when the parent channel is closed, whichever happens first.
257
+ //
258
+ // Note the caller must *always* call the CancelFunc, otherwise resources may be leaked.
259
+ func contextForChannel (parentCh <- chan struct {}) (context.Context , context.CancelFunc ) {
260
+ ctx , cancel := context .WithCancel (context .Background ())
261
+
262
+ go func () {
263
+ select {
264
+ case <- parentCh :
265
+ cancel ()
266
+ case <- ctx .Done ():
267
+ }
268
+ }()
269
+ return ctx , cancel
270
+ }
271
+
253
272
// ExponentialBackoff repeats a condition check with exponential backoff.
254
273
//
255
274
// It checks the condition up to Steps times, increasing the wait by multiplying
@@ -353,7 +372,9 @@ func PollImmediateInfinite(interval time.Duration, condition ConditionFunc) erro
353
372
// PollUntil always waits interval before the first run of 'condition'.
354
373
// 'condition' will always be invoked at least once.
355
374
func PollUntil (interval time.Duration , condition ConditionFunc , stopCh <- chan struct {}) error {
356
- return WaitFor (poller (interval , 0 ), condition , stopCh )
375
+ ctx , cancel := contextForChannel (stopCh )
376
+ defer cancel ()
377
+ return WaitFor (poller (interval , 0 ), condition , ctx .Done ())
357
378
}
358
379
359
380
// PollImmediateUntil tries a condition func until it returns true, an error or stopCh is closed.
@@ -422,7 +443,9 @@ func WaitFor(wait WaitFunc, fn ConditionFunc, done <-chan struct{}) error {
422
443
// timeout has elapsed and then closes the channel.
423
444
//
424
445
// Over very short intervals you may receive no ticks before the channel is
425
- // closed. A timeout of 0 is interpreted as an infinity.
446
+ // closed. A timeout of 0 is interpreted as an infinity, and in such a case
447
+ // it would be the caller's responsibility to close the done channel.
448
+ // Failure to do so would result in a leaked goroutine.
426
449
//
427
450
// Output ticks are not buffered. If the channel is not ready to receive an
428
451
// item, the tick is skipped.
0 commit comments