Currently Manager.Start immediately returns when stop channel is closed without waiting for Runnables to stop:
|
select { |
|
case <-stop: |
|
// We are done |
|
return nil |
This makes writing a Runnable with blocking stop logic difficult or impossible. For example, the Manager's internal serveMetrics is basically a Runnable (a blocking method that takes a stop channel). When the stop channel is closed, serveMetrics tries to shut down its http server:
|
select { |
|
case <-stop: |
|
if err := server.Shutdown(context.Background()); err != nil { |
|
cm.errChan <- err |
|
} |
But in normal usage, the process immediately exits when Manager.Start returns so the Shutdown call is unlikely to complete.
Adding sync.WaitGroup accounting inside the Runnable wrapper goroutines would allow the addition of a Wait() method to the Manager interface that blocks until all Runnables have returned (or WaitWithTimeout(time.Duration), Shutdown(context.Context) for a termination timeout), without changing either the Runnable contract or the Manager contract:
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
log.Error(err, "unable to run the manager")
os.Exit(1)
}
mgr.Wait()
Currently
Manager.Startimmediately returns when stop channel is closed without waiting for Runnables to stop:controller-runtime/pkg/manager/internal.go
Lines 216 to 219 in 6649bdb
This makes writing a Runnable with blocking stop logic difficult or impossible. For example, the Manager's internal
serveMetricsis basically a Runnable (a blocking method that takes a stop channel). When the stop channel is closed,serveMetricstries to shut down its http server:controller-runtime/pkg/manager/internal.go
Lines 188 to 192 in 6649bdb
But in normal usage, the process immediately exits when Manager.Start returns so the
Shutdowncall is unlikely to complete.Adding
sync.WaitGroupaccounting inside the Runnable wrapper goroutines would allow the addition of aWait()method to theManagerinterface that blocks until all Runnables have returned (orWaitWithTimeout(time.Duration),Shutdown(context.Context)for a termination timeout), without changing either the Runnable contract or the Manager contract: