diff options
Diffstat (limited to 'signal/signal.go')
-rw-r--r-- | signal/signal.go | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/signal/signal.go b/signal/signal.go new file mode 100644 index 0000000..96ef5f7 --- /dev/null +++ b/signal/signal.go @@ -0,0 +1,60 @@ +package signal + +import ( + "io" + "os" + "os/signal" + "syscall" + + "github.com/mpolden/zdns/log" +) + +// Reloader is the interface for types that need to act on a reload signal. +type Reloader interface { + Reload() +} + +// Handler represents a signal handler and holds references to types that should act on operating system signals. +type Handler struct { + logger *log.Logger + signal chan os.Signal + reloaders []Reloader + closers []io.Closer +} + +// NewHandler creates a new handler for handling operating system signals. +func NewHandler(c chan os.Signal, logger *log.Logger) *Handler { + h := &Handler{logger: logger, signal: c} + signal.Notify(h.signal) + go h.readSignal() + return h +} + +// OnReload registers a reloader to call for the signal SIGHUP. +func (s *Handler) OnReload(r Reloader) { s.reloaders = append(s.reloaders, r) } + +// OnClose registers a closer to call for signals SIGTERM and SIGINT. +func (s *Handler) OnClose(c io.Closer) { s.closers = append(s.closers, c) } + +func (s *Handler) readSignal() { + for sig := range s.signal { + switch sig { + case syscall.SIGHUP: + s.logger.Printf("received signal %s: reloading", sig) + for _, r := range s.reloaders { + r.Reload() + } + case syscall.SIGTERM, syscall.SIGINT: + signal.Stop(s.signal) + s.logger.Printf("received signal %s: shutting down", sig) + for _, c := range s.closers { + if err := c.Close(); err != nil { + s.logger.Printf("close failed: %s", err) + } + } + + default: + s.logger.Printf("received signal %s: ignoring", sig) + } + } +} |