diff --git a/pkg/controller/resourcequota/resource_quota_monitor.go b/pkg/controller/resourcequota/resource_quota_monitor.go index d0d0f30b975..6e894a7941f 100644 --- a/pkg/controller/resourcequota/resource_quota_monitor.go +++ b/pkg/controller/resourcequota/resource_quota_monitor.go @@ -78,8 +78,9 @@ type QuotaMonitor struct { // This channel is also protected by monitorLock. stopCh <-chan struct{} - // running tracks whether Run() has been called. - // it is protected by monitorLock. + // running is set to true when the Run() function has been called. + // It will revert to false when the Run() function receives a cancellation. + // It is protected by monitorLock. running bool // monitors are the producer of the resourceChanges queue @@ -331,6 +332,10 @@ func (qm *QuotaMonitor) Run(ctx context.Context) { // Stop any running monitors. qm.monitorLock.Lock() defer qm.monitorLock.Unlock() + // Mark as not running so that no new monitors can be started. + // Not doing this here could cause goroutine leaks and deadlocks since it would make it possible for startMonitors + // to proceed and start new monitors after stopMonitors has been called. + qm.running = false monitors := qm.monitors stopped := 0 for _, monitor := range monitors { @@ -339,6 +344,7 @@ func (qm *QuotaMonitor) Run(ctx context.Context) { close(monitor.stopCh) } } + qm.monitors = nil logger.Info("QuotaMonitor stopped monitors", "stopped", stopped, "total", len(monitors)) }