mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Merge pull request #71326 from shomron/issue-71277-polluntil-leak
Fix goroutine leak in pkg/util/wait PollUntil()
This commit is contained in:
		@@ -250,6 +250,25 @@ func (b *Backoff) Step() time.Duration {
 | 
			
		||||
	return duration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// contextForChannel derives a child context from a parent channel.
 | 
			
		||||
//
 | 
			
		||||
// The derived context's Done channel is closed when the returned cancel function
 | 
			
		||||
// is called or when the parent channel is closed, whichever happens first.
 | 
			
		||||
//
 | 
			
		||||
// Note the caller must *always* call the CancelFunc, otherwise resources may be leaked.
 | 
			
		||||
func contextForChannel(parentCh <-chan struct{}) (context.Context, context.CancelFunc) {
 | 
			
		||||
	ctx, cancel := context.WithCancel(context.Background())
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-parentCh:
 | 
			
		||||
			cancel()
 | 
			
		||||
		case <-ctx.Done():
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	return ctx, cancel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ExponentialBackoff repeats a condition check with exponential backoff.
 | 
			
		||||
//
 | 
			
		||||
// 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
 | 
			
		||||
// PollUntil always waits interval before the first run of 'condition'.
 | 
			
		||||
// 'condition' will always be invoked at least once.
 | 
			
		||||
func PollUntil(interval time.Duration, condition ConditionFunc, stopCh <-chan struct{}) error {
 | 
			
		||||
	return WaitFor(poller(interval, 0), condition, stopCh)
 | 
			
		||||
	ctx, cancel := contextForChannel(stopCh)
 | 
			
		||||
	defer cancel()
 | 
			
		||||
	return WaitFor(poller(interval, 0), condition, ctx.Done())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 {
 | 
			
		||||
// timeout has elapsed and then closes the channel.
 | 
			
		||||
//
 | 
			
		||||
// Over very short intervals you may receive no ticks before the channel is
 | 
			
		||||
// closed. A timeout of 0 is interpreted as an infinity.
 | 
			
		||||
// closed. A timeout of 0 is interpreted as an infinity, and in such a case
 | 
			
		||||
// it would be the caller's responsibility to close the done channel.
 | 
			
		||||
// Failure to do so would result in a leaked goroutine.
 | 
			
		||||
//
 | 
			
		||||
// Output ticks are not buffered. If the channel is not ready to receive an
 | 
			
		||||
// item, the tick is skipped.
 | 
			
		||||
 
 | 
			
		||||
@@ -664,3 +664,33 @@ func TestBackoff_Step(t *testing.T) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestContextForChannel(t *testing.T) {
 | 
			
		||||
	var wg sync.WaitGroup
 | 
			
		||||
	parentCh := make(chan struct{})
 | 
			
		||||
	done := make(chan struct{})
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < 3; i++ {
 | 
			
		||||
		wg.Add(1)
 | 
			
		||||
		go func() {
 | 
			
		||||
			defer wg.Done()
 | 
			
		||||
			ctx, cancel := contextForChannel(parentCh)
 | 
			
		||||
			defer cancel()
 | 
			
		||||
			<-ctx.Done()
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		wg.Wait()
 | 
			
		||||
		close(done)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	// Closing parent channel should cancel all children contexts
 | 
			
		||||
	close(parentCh)
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-done:
 | 
			
		||||
	case <-time.After(ForeverTestTimeout):
 | 
			
		||||
		t.Errorf("unexepcted timeout waiting for parent to cancel child contexts")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user