mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
windows/svc: workaround-exit mechanism that works for signal-less binaries
This commit is contained in:
parent
f243c88779
commit
afdfe8d558
@ -19,6 +19,9 @@ limitations under the License.
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"k8s.io/apiserver/pkg/server"
|
"k8s.io/apiserver/pkg/server"
|
||||||
"k8s.io/klog"
|
"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.
|
// 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
|
// Since Windows services do not use any console, we cannot simply generate a CTRL_BREAK_EVENT
|
||||||
// but need a dedicated notification mechanism.
|
// but need a dedicated notification mechanism.
|
||||||
server.RequestShutdown()
|
graceful := server.RequestShutdown()
|
||||||
|
|
||||||
// Free up the control handler and let us terminate as gracefully as possible.
|
// 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.
|
// 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
|
// As per https://docs.microsoft.com/en-us/windows/desktop/services/service-control-handler-function
|
||||||
s <- svc.Status{State: svc.StopPending}
|
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
|
break Loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var onlyOneSignalHandler = make(chan struct{})
|
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
|
// 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
|
// 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{} {
|
func SetupSignalHandler() <-chan struct{} {
|
||||||
close(onlyOneSignalHandler) // panics when called twice
|
close(onlyOneSignalHandler) // panics when called twice
|
||||||
|
|
||||||
|
shutdownHandler = make(chan os.Signal, 2)
|
||||||
|
|
||||||
stop := make(chan struct{})
|
stop := make(chan struct{})
|
||||||
signal.Notify(shutdownHandler, shutdownSignals...)
|
signal.Notify(shutdownHandler, shutdownSignals...)
|
||||||
go func() {
|
go func() {
|
||||||
@ -43,9 +45,15 @@ func SetupSignalHandler() <-chan struct{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RequestShutdown emulates a received event that is considered as shutdown signal (SIGTERM/SIGINT)
|
// RequestShutdown emulates a received event that is considered as shutdown signal (SIGTERM/SIGINT)
|
||||||
func RequestShutdown() {
|
// This returns whether a handler was notified
|
||||||
select {
|
func RequestShutdown() bool {
|
||||||
case shutdownHandler <- shutdownSignals[0]:
|
if shutdownHandler != nil {
|
||||||
default:
|
select {
|
||||||
|
case shutdownHandler <- shutdownSignals[0]:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user