apiserver: move the signal handlers into a stdlib-only leaf package

k8s.io/apiserver/pkg/server/signals now owns the shared SIGTERM/SIGINT
handler. server keeps SetupSignalHandler, SetupSignalContext and
RequestShutdown as wrappers, so existing callers and the single
shutdown state are unchanged. pkg/windows/service imports the leaf,
which takes the generic API server, and with it the CEL stack, out of
kube-proxy.exe.

Signed-off-by: Davanum Srinivas <davanum@gmail.com>
This commit is contained in:
Davanum Srinivas committed 2026-09-28 09:00:19 -04:00
1 parent 6c1c7702cf
commit 8853403147
5 files changed
+85 -43

No files matched your search

+2 -2
View File
@@ -24,7 +24,7 @@ import (
"time"
"unsafe"
"k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/signals"
"k8s.io/klog/v2"
"golang.org/x/sys/windows"
@@ -171,7 +171,7 @@ 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.
graceful := server.RequestShutdown()
graceful := signals.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.
@@ -18,52 +18,23 @@ package server
import (
"context"
"os"
"os/signal"
"k8s.io/apiserver/pkg/server/signals"
)
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
// is terminated with exit code 1.
// Only one of SetupSignalContext and SetupSignalHandler should be called, and only can
// be called once.
// SetupSignalHandler is signals.SetupSignalHandler. The wrappers in this file
// keep the published API and the single shared shutdown state for existing
// callers.
func SetupSignalHandler() <-chan struct{} {
return SetupSignalContext().Done()
return signals.SetupSignalHandler()
}
// SetupSignalContext is same as SetupSignalHandler, but a context.Context is returned.
// Only one of SetupSignalContext and SetupSignalHandler should be called, and only can
// be called once.
// SetupSignalContext is signals.SetupSignalContext.
func SetupSignalContext() context.Context {
close(onlyOneSignalHandler) // panics when called twice
shutdownHandler = make(chan os.Signal, 2)
ctx, cancel := context.WithCancel(context.Background())
signal.Notify(shutdownHandler, shutdownSignals...)
go func() {
<-shutdownHandler
cancel()
<-shutdownHandler
os.Exit(1) // second signal. Exit directly.
}()
return ctx
return signals.SetupSignalContext()
}
// RequestShutdown emulates a received event that is considered as shutdown signal (SIGTERM/SIGINT)
// This returns whether a handler was notified
// RequestShutdown is signals.RequestShutdown.
func RequestShutdown() bool {
if shutdownHandler != nil {
select {
case shutdownHandler <- shutdownSignals[0]:
return true
default:
}
}
return false
return signals.RequestShutdown()
}
@@ -0,0 +1,71 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package signals installs the shared SIGTERM and SIGINT shutdown handler.
// It depends only on the standard library.
package signals
import (
"context"
"os"
"os/signal"
)
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
// is terminated with exit code 1.
// Only one of SetupSignalContext and SetupSignalHandler should be called, and only can
// be called once.
func SetupSignalHandler() <-chan struct{} {
return SetupSignalContext().Done()
}
// SetupSignalContext is same as SetupSignalHandler, but a context.Context is returned.
// Only one of SetupSignalContext and SetupSignalHandler should be called, and only can
// be called once.
func SetupSignalContext() context.Context {
close(onlyOneSignalHandler) // panics when called twice
shutdownHandler = make(chan os.Signal, 2)
ctx, cancel := context.WithCancel(context.Background())
signal.Notify(shutdownHandler, shutdownSignals...)
go func() {
<-shutdownHandler
cancel()
<-shutdownHandler
os.Exit(1) // second signal. Exit directly.
}()
return ctx
}
// 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
}
@@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package server
package signals
import (
"os"
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package server
package signals
import (
"os"