Files
weave-scope/vendor/github.com/weaveworks/common/signals/signals.go
2020-01-21 16:26:13 +00:00

74 lines
1.7 KiB
Go

package signals
import (
"os"
"os/signal"
"runtime"
"syscall"
"github.com/weaveworks/common/logging"
)
// SignalReceiver represents a subsystem/server/... that can be stopped or
// queried about the status with a signal
type SignalReceiver interface {
Stop() error
}
// Handler handles signals, can be interrupted.
// On SIGINT or SIGTERM it will exit, on SIGQUIT it
// will dump goroutine stacks to the Logger.
type Handler struct {
log logging.Interface
receivers []SignalReceiver
quit chan struct{}
}
// NewHandler makes a new Handler.
func NewHandler(log logging.Interface, receivers ...SignalReceiver) *Handler {
return &Handler{
log: log,
receivers: receivers,
quit: make(chan struct{}),
}
}
// Stop the handler
func (h *Handler) Stop() {
close(h.quit)
}
// Loop handles signals.
func (h *Handler) Loop() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
defer signal.Stop(sigs)
buf := make([]byte, 1<<20)
for {
select {
case <-h.quit:
h.log.Infof("=== Handler.Stop()'d ===")
return
case sig := <-sigs:
switch sig {
case syscall.SIGINT, syscall.SIGTERM:
h.log.Infof("=== received SIGINT/SIGTERM ===\n*** exiting")
for _, subsystem := range h.receivers {
subsystem.Stop()
}
return
case syscall.SIGQUIT:
stacklen := runtime.Stack(buf, true)
h.log.Infof("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end", buf[:stacklen])
}
}
}
}
// SignalHandlerLoop blocks until it receives a SIGINT, SIGTERM or SIGQUIT.
// For SIGINT and SIGTERM, it exits; for SIGQUIT is print a goroutine stack
// dump.
func SignalHandlerLoop(log logging.Interface, ss ...SignalReceiver) {
NewHandler(log, ss...).Loop()
}