diff --git a/go.mod b/go.mod index 41c70690..9f47b8f9 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( golang.org/x/time v0.3.0 google.golang.org/protobuf v1.34.2 gopkg.in/evanphx/json-patch.v4 v4.12.0 - k8s.io/api v0.0.0-20240722223049-b689d905290f + k8s.io/api v0.0.0-20240723194852-3421a80713ae k8s.io/apimachinery v0.0.0-20240720202316-95b78024e3fe k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 diff --git a/go.sum b/go.sum index c6d48902..28e1d1c4 100644 --- a/go.sum +++ b/go.sum @@ -156,8 +156,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.0.0-20240722223049-b689d905290f h1:wtqzslJEcheiQ7hXjw1yGfqUyMCb7G4j72aL64Bzpbo= -k8s.io/api v0.0.0-20240722223049-b689d905290f/go.mod h1:ytlEzqC2wOTwYET71W7+J+k7O2V7vrDuzmNLBSpgT+k= +k8s.io/api v0.0.0-20240723194852-3421a80713ae h1:mV43yijQh5/Wf7fwSuyATasDFY+YJxjuXs1ecY5M1Bc= +k8s.io/api v0.0.0-20240723194852-3421a80713ae/go.mod h1:ytlEzqC2wOTwYET71W7+J+k7O2V7vrDuzmNLBSpgT+k= k8s.io/apimachinery v0.0.0-20240720202316-95b78024e3fe h1:V9MwpYUwbKlfLKVrhpVuKWiat/LBIhm1pGB9/xdHm5Q= k8s.io/apimachinery v0.0.0-20240720202316-95b78024e3fe/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= diff --git a/tools/watch/retrywatcher.go b/tools/watch/retrywatcher.go index d81dc435..8431d02f 100644 --- a/tools/watch/retrywatcher.go +++ b/tools/watch/retrywatcher.go @@ -22,6 +22,7 @@ import ( "fmt" "io" "net/http" + "sync" "time" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -53,6 +54,7 @@ type RetryWatcher struct { stopChan chan struct{} doneChan chan struct{} minRestartDelay time.Duration + stopChanLock sync.Mutex } // NewRetryWatcher creates a new RetryWatcher. @@ -286,7 +288,15 @@ func (rw *RetryWatcher) ResultChan() <-chan watch.Event { // Stop implements Interface. func (rw *RetryWatcher) Stop() { - close(rw.stopChan) + rw.stopChanLock.Lock() + defer rw.stopChanLock.Unlock() + + // Prevent closing an already closed channel to prevent a panic + select { + case <-rw.stopChan: + default: + close(rw.stopChan) + } } // Done allows the caller to be notified when Retry watcher stops. diff --git a/tools/watch/retrywatcher_test.go b/tools/watch/retrywatcher_test.go index fff3a46c..297661aa 100644 --- a/tools/watch/retrywatcher_test.go +++ b/tools/watch/retrywatcher_test.go @@ -585,6 +585,8 @@ func TestRetryWatcherToFinishWithUnreadEvents(t *testing.T) { // Give the watcher a chance to get to sending events (blocking) time.Sleep(10 * time.Millisecond) + watcher.Stop() + // Verify a second stop does not cause a panic watcher.Stop() maxTime := time.Second