diff --git a/pkg/windows/service/service.go b/pkg/windows/service/service.go index 28b531ae77c..47961b842ef 100644 --- a/pkg/windows/service/service.go +++ b/pkg/windows/service/service.go @@ -19,6 +19,9 @@ limitations under the License. package service import ( + "os" + "time" + "k8s.io/apiserver/pkg/server" "k8s.io/klog" @@ -85,12 +88,24 @@ Loop: // If we do not do this, our main threads won't be notified of the upcoming shutdown. // Since Windows services do not use any console, we cannot simply generate a CTRL_BREAK_EVENT // but need a dedicated notification mechanism. - server.RequestShutdown() + graceful := server.RequestShutdown() // Free up the control handler and let us terminate as gracefully as possible. // If that takes too long, the service controller will kill the remaining threads. // As per https://docs.microsoft.com/en-us/windows/desktop/services/service-control-handler-function s <- svc.Status{State: svc.StopPending} + + // If we cannot exit gracefully, we really only can exit our process, so atleast the + // service manager will think that we gracefully exited. At the time of writing this comment this is + // needed for applications that do not use signals (e.g. kube-proxy) + if !graceful { + go func() { + // Ensure the SCM was notified (The operation above (send to s) was received and communicated to the + // service control manager - so it doesn't look like the service crashes) + time.Sleep(1 * time.Second) + os.Exit(0) + }() + } break Loop } } diff --git a/staging/src/k8s.io/apiserver/pkg/server/signal.go b/staging/src/k8s.io/apiserver/pkg/server/signal.go index 6f3edbba470..0ea19d6606d 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/signal.go +++ b/staging/src/k8s.io/apiserver/pkg/server/signal.go @@ -22,7 +22,7 @@ import ( ) var onlyOneSignalHandler = make(chan struct{}) -var shutdownHandler = make(chan os.Signal, 2) +var shutdownHandler chan os.Signal // SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned // which is closed on one of these signals. If a second signal is caught, the program @@ -30,6 +30,8 @@ var shutdownHandler = make(chan os.Signal, 2) func SetupSignalHandler() <-chan struct{} { close(onlyOneSignalHandler) // panics when called twice + shutdownHandler = make(chan os.Signal, 2) + stop := make(chan struct{}) signal.Notify(shutdownHandler, shutdownSignals...) go func() { @@ -43,9 +45,15 @@ func SetupSignalHandler() <-chan struct{} { } // RequestShutdown emulates a received event that is considered as shutdown signal (SIGTERM/SIGINT) -func RequestShutdown() { - select { - case shutdownHandler <- shutdownSignals[0]: - default: +// This returns whether a handler was notified +func RequestShutdown() bool { + if shutdownHandler != nil { + select { + case shutdownHandler <- shutdownSignals[0]: + return true + default: + } } + + return false }