mirror of https://github.com/k3s-io/k3s
Merge pull request #73292 from steffengy/master
windows/service: implement graceful shutdown when run as windows servicepull/564/head
commit
296985ce35
|
@ -11,6 +11,7 @@ go_library(
|
|||
importpath = "k8s.io/kubernetes/pkg/windows/service",
|
||||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:windows": [
|
||||
"//staging/src/k8s.io/apiserver/pkg/server:go_default_library",
|
||||
"//vendor/golang.org/x/sys/windows:go_default_library",
|
||||
"//vendor/golang.org/x/sys/windows/svc:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
|
|
|
@ -20,7 +20,9 @@ package service
|
|||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/klog"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
@ -80,9 +82,31 @@ Loop:
|
|||
case svc.Interrogate:
|
||||
s <- c.CurrentStatus
|
||||
case svc.Stop, svc.Shutdown:
|
||||
s <- svc.Status{State: svc.Stopped}
|
||||
// TODO: Stop the kubelet gracefully instead of killing the process
|
||||
os.Exit(0)
|
||||
klog.Infof("Service stopping")
|
||||
// We need to translate this request into a signal that can be handled by the the signal handler
|
||||
// handling shutdowns normally (currently apiserver/pkg/server/signal.go).
|
||||
// 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.
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
)
|
||||
|
||||
var onlyOneSignalHandler = make(chan struct{})
|
||||
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
|
||||
|
@ -29,15 +30,30 @@ var onlyOneSignalHandler = make(chan struct{})
|
|||
func SetupSignalHandler() <-chan struct{} {
|
||||
close(onlyOneSignalHandler) // panics when called twice
|
||||
|
||||
shutdownHandler = make(chan os.Signal, 2)
|
||||
|
||||
stop := make(chan struct{})
|
||||
c := make(chan os.Signal, 2)
|
||||
signal.Notify(c, shutdownSignals...)
|
||||
signal.Notify(shutdownHandler, shutdownSignals...)
|
||||
go func() {
|
||||
<-c
|
||||
<-shutdownHandler
|
||||
close(stop)
|
||||
<-c
|
||||
<-shutdownHandler
|
||||
os.Exit(1) // second signal. Exit directly.
|
||||
}()
|
||||
|
||||
return stop
|
||||
}
|
||||
|
||||
// RequestShutdown emulates a received event that is considered as shutdown signal (SIGTERM/SIGINT)
|
||||
// This returns whether a handler was notified
|
||||
func RequestShutdown() bool {
|
||||
if shutdownHandler != nil {
|
||||
select {
|
||||
case shutdownHandler <- shutdownSignals[0]:
|
||||
return true
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue