From b97609cd2cee8b84f527c8b60dfd5df8dcee1447 Mon Sep 17 00:00:00 2001 From: Jamie Holdstock Date: Thu, 26 Aug 2021 15:28:51 +0100 Subject: [PATCH] Update shutdown signalling. (#293) Bring in some updates from the signal handling code in other projects: - Rename `signals` to more descriptive `interruptSignals`. - Add SIGHUP to unix shutdown signals. Rename `signalsigterm.go` to `signal_unix.go` accordingly. - Include extra detail in "Already shutting down..." messages log lines. - Pass a shutdown func into `webapi.go` rather than a channel. It's more obvious how to invoke a func, whereas a channel can be used in multiple ways. --- signal.go | 20 +++++++++++--------- signalsigterm.go => signal_unix.go | 7 ++++++- vspd.go | 2 +- webapi/webapi.go | 4 ++-- 4 files changed, 20 insertions(+), 13 deletions(-) rename signalsigterm.go => signal_unix.go (66%) diff --git a/signal.go b/signal.go index 8724183..b358aca 100644 --- a/signal.go +++ b/signal.go @@ -1,4 +1,5 @@ // Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -19,9 +20,9 @@ var shutdownRequestChannel = make(chan struct{}) // withShutdownChannel are cancelled when this is closed. var shutdownSignaled = make(chan struct{}) -// signals defines the signals that are handled to do a clean shutdown. -// Conditional compilation is used to also include SIGTERM on Unix. -var signals = []os.Signal{os.Interrupt} +// interruptSignals defines the signals that are handled to do a clean shutdown. +// Conditional compilation is used to also include SIGTERM and SIGHUP on Unix. +var interruptSignals = []os.Signal{os.Interrupt} // withShutdownCancel creates a copy of a context that is cancelled whenever // shutdown is invoked through an interrupt signal or from an JSON-RPC stop @@ -36,7 +37,7 @@ func withShutdownCancel(ctx context.Context) context.Context { } // requestShutdown signals for starting the clean shutdown of the process -// through an internal component (such as through the JSON-RPC stop request). +// through an internal component. func requestShutdown() { shutdownRequestChannel <- struct{}{} } @@ -46,14 +47,14 @@ func requestShutdown() { // to be spawned in a new goroutine. func shutdownListener() { interruptChannel := make(chan os.Signal, 1) - signal.Notify(interruptChannel, signals...) + signal.Notify(interruptChannel, interruptSignals...) // Listen for the initial shutdown signal select { case sig := <-interruptChannel: - log.Infof("Received signal (%s). Shutting down...", sig) + log.Infof("Received signal (%s). Shutting down...", sig) case <-shutdownRequestChannel: - log.Info("Shutdown requested. Shutting down...") + log.Info("Shutdown requested. Shutting down...") } // Cancel all contexts created from withShutdownCancel. @@ -63,9 +64,10 @@ func shutdownListener() { // been signaled. for { select { - case <-interruptChannel: + case sig := <-interruptChannel: + log.Infof("Received signal (%s). Already shutting down...", sig) case <-shutdownRequestChannel: + log.Info("Shutdown requested. Already shutting down...") } - log.Info("Shutdown signaled. Already shutting down...") } } diff --git a/signalsigterm.go b/signal_unix.go similarity index 66% rename from signalsigterm.go rename to signal_unix.go index 7aaa39a..4d550e3 100644 --- a/signalsigterm.go +++ b/signal_unix.go @@ -1,4 +1,5 @@ // Copyright (c) 2016 The btcsuite developers +// Copyright (c) 2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -12,5 +13,9 @@ import ( ) func init() { - signals = []os.Signal{os.Interrupt, syscall.SIGTERM} + interruptSignals = []os.Signal{ + os.Interrupt, + syscall.SIGTERM, + syscall.SIGHUP, + } } diff --git a/vspd.go b/vspd.go index 3eba344..f9922e1 100644 --- a/vspd.go +++ b/vspd.go @@ -104,7 +104,7 @@ func run(ctx context.Context) error { MaxVoteChangeRecords: maxVoteChangeRecords, VspdVersion: version.String(), } - err = webapi.Start(ctx, shutdownRequestChannel, &shutdownWg, cfg.Listen, db, + err = webapi.Start(ctx, requestShutdown, &shutdownWg, cfg.Listen, db, dcrd, wallets, apiCfg) if err != nil { log.Errorf("Failed to initialize webapi: %v", err) diff --git a/webapi/webapi.go b/webapi/webapi.go index 5bc9392..1b59ebf 100644 --- a/webapi/webapi.go +++ b/webapi/webapi.go @@ -55,7 +55,7 @@ var addrGen *addressGenerator var signPrivKey ed25519.PrivateKey var signPubKey ed25519.PublicKey -func Start(ctx context.Context, requestShutdownChan chan struct{}, shutdownWg *sync.WaitGroup, +func Start(ctx context.Context, requestShutdown func(), shutdownWg *sync.WaitGroup, listen string, vdb *database.VspDatabase, dcrd rpc.DcrdConnect, wallets rpc.WalletConnect, config Config) error { cfg = config @@ -137,7 +137,7 @@ func Start(ctx context.Context, requestShutdownChan chan struct{}, shutdownWg *s // shutdown. if err != nil && !errors.Is(err, http.ErrServerClosed) { log.Errorf("Unexpected webserver error: %v", err) - requestShutdownChan <- struct{}{} + requestShutdown() } }()