diff --git a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go index ee11c5d0a20..000c52e8b7c 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go +++ b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go @@ -437,7 +437,7 @@ func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer { // | | // (ShutdownDelayDuration) (PreShutdownHooks) // | | -// AfterShutdownDelayDuration (delayedStopCh) preShutdownHooksHasStoppedCh +// AfterShutdownDelayDuration (delayedStopCh) PreShutdownHooksStopped (preShutdownHooksHasStoppedCh) // | | // |---------------------------------- | // | | | @@ -510,12 +510,13 @@ func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error { } // pre-shutdown hooks need to finish before we stop the http server - preShutdownHooksHasStoppedCh, stopHttpServerCh := make(chan struct{}), make(chan struct{}) + preShutdownHooksHasStoppedCh := s.lifecycleSignals.PreShutdownHooksStopped + stopHttpServerCh := make(chan struct{}) go func() { defer close(stopHttpServerCh) <-delayedStopOrDrainedCh - <-preShutdownHooksHasStoppedCh + <-preShutdownHooksHasStoppedCh.Signaled() }() // Start the audit backend before any request comes in. This means we must call Backend.Run @@ -556,7 +557,10 @@ func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error { // run shutdown hooks directly. This includes deregistering from // the kubernetes endpoint in case of kube-apiserver. func() { - defer close(preShutdownHooksHasStoppedCh) + defer func() { + preShutdownHooksHasStoppedCh.Signal() + klog.V(1).InfoS("[graceful-termination] pre-shutdown hooks completed", "name", preShutdownHooksHasStoppedCh.Name()) + }() err = s.RunPreShutdownHooks() }() if err != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/server/lifecycle_signals.go b/staging/src/k8s.io/apiserver/pkg/server/lifecycle_signals.go index 6b406072b61..fd1c94db2db 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/lifecycle_signals.go +++ b/staging/src/k8s.io/apiserver/pkg/server/lifecycle_signals.go @@ -120,6 +120,10 @@ type lifecycleSignals struct { // ShutdownDelayDuration allows the apiserver to delay shutdown for some time. AfterShutdownDelayDuration lifecycleSignal + // PreShutdownHooksStopped event is signaled when all registered + // preshutdown hook(s) have finished running. + PreShutdownHooksStopped lifecycleSignal + // InFlightRequestsDrained event is signaled when the existing requests // in flight have completed. This is used as signal to shut down the audit backends InFlightRequestsDrained lifecycleSignal @@ -143,6 +147,7 @@ func newLifecycleSignals() lifecycleSignals { return lifecycleSignals{ ShutdownInitiated: newNamedChannelWrapper("ShutdownInitiated"), AfterShutdownDelayDuration: newNamedChannelWrapper("AfterShutdownDelayDuration"), + PreShutdownHooksStopped: newNamedChannelWrapper("PreShutdownHooksStopped"), InFlightRequestsDrained: newNamedChannelWrapper("InFlightRequestsDrained"), HTTPServerStoppedListening: newNamedChannelWrapper("HTTPServerStoppedListening"), HasBeenReady: newNamedChannelWrapper("HasBeenReady"),