Merge pull request #1392 from cfromknecht/signal-package
Signal/Interrupt package
This commit is contained in:
commit
ff771968b6
37
lnd.go
37
lnd.go
@ -35,7 +35,6 @@ import (
|
|||||||
|
|
||||||
proxy "github.com/grpc-ecosystem/grpc-gateway/runtime"
|
proxy "github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||||
flags "github.com/jessevdk/go-flags"
|
flags "github.com/jessevdk/go-flags"
|
||||||
"github.com/lightningnetwork/lnd/autopilot"
|
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lncfg"
|
"github.com/lightningnetwork/lnd/lncfg"
|
||||||
@ -44,6 +43,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
|
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/macaroons"
|
"github.com/lightningnetwork/lnd/macaroons"
|
||||||
|
"github.com/lightningnetwork/lnd/signal"
|
||||||
"github.com/lightningnetwork/lnd/walletunlocker"
|
"github.com/lightningnetwork/lnd/walletunlocker"
|
||||||
"github.com/roasbeef/btcd/btcec"
|
"github.com/roasbeef/btcd/btcec"
|
||||||
"github.com/roasbeef/btcd/wire"
|
"github.com/roasbeef/btcd/wire"
|
||||||
@ -62,7 +62,6 @@ var (
|
|||||||
Commit string
|
Commit string
|
||||||
|
|
||||||
cfg *config
|
cfg *config
|
||||||
shutdownChannel = make(chan struct{})
|
|
||||||
registeredChains = newChainRegistry()
|
registeredChains = newChainRegistry()
|
||||||
|
|
||||||
macaroonDatabaseDir string
|
macaroonDatabaseDir string
|
||||||
@ -94,6 +93,8 @@ var (
|
|||||||
// defers created in the top-level scope of a main method aren't executed if
|
// defers created in the top-level scope of a main method aren't executed if
|
||||||
// os.Exit() is called.
|
// os.Exit() is called.
|
||||||
func lndMain() error {
|
func lndMain() error {
|
||||||
|
defer ltndLog.Info("Shutdown complete")
|
||||||
|
|
||||||
// Load the configuration, and parse any command line options. This
|
// Load the configuration, and parse any command line options. This
|
||||||
// function will also set up logging properly.
|
// function will also set up logging properly.
|
||||||
loadedConfig, err := loadConfig()
|
loadedConfig, err := loadConfig()
|
||||||
@ -500,6 +501,7 @@ func lndMain() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
server.fundingMgr = fundingMgr
|
server.fundingMgr = fundingMgr
|
||||||
|
defer fundingMgr.Stop()
|
||||||
|
|
||||||
// Check macaroon authentication if macaroons aren't disabled.
|
// Check macaroon authentication if macaroons aren't disabled.
|
||||||
if macaroonService != nil {
|
if macaroonService != nil {
|
||||||
@ -517,6 +519,7 @@ func lndMain() error {
|
|||||||
if err := rpcServer.Start(); err != nil {
|
if err := rpcServer.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer rpcServer.Stop()
|
||||||
|
|
||||||
grpcServer := grpc.NewServer(serverOpts...)
|
grpcServer := grpc.NewServer(serverOpts...)
|
||||||
lnrpc.RegisterLightningServer(grpcServer, rpcServer)
|
lnrpc.RegisterLightningServer(grpcServer, rpcServer)
|
||||||
@ -574,18 +577,9 @@ func lndMain() error {
|
|||||||
ltndLog.Infof("Waiting for chain backend to finish sync, "+
|
ltndLog.Infof("Waiting for chain backend to finish sync, "+
|
||||||
"start_height=%v", bestHeight)
|
"start_height=%v", bestHeight)
|
||||||
|
|
||||||
// We'll add an interrupt handler in order to process shutdown
|
|
||||||
// requests while the chain backend syncs.
|
|
||||||
addInterruptHandler(func() {
|
|
||||||
rpcServer.Stop()
|
|
||||||
fundingMgr.Stop()
|
|
||||||
})
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
if !signal.Alive() {
|
||||||
case <-shutdownChannel:
|
|
||||||
return nil
|
return nil
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
synced, _, err := activeChainControl.wallet.IsSynced()
|
synced, _, err := activeChainControl.wallet.IsSynced()
|
||||||
@ -615,10 +609,10 @@ func lndMain() error {
|
|||||||
srvrLog.Errorf("unable to start server: %v\n", err)
|
srvrLog.Errorf("unable to start server: %v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer server.Stop()
|
||||||
|
|
||||||
// Now that the server has started, if the autopilot mode is currently
|
// Now that the server has started, if the autopilot mode is currently
|
||||||
// active, then we'll initialize a fresh instance of it and start it.
|
// active, then we'll initialize a fresh instance of it and start it.
|
||||||
var pilot *autopilot.Agent
|
|
||||||
if cfg.Autopilot.Active {
|
if cfg.Autopilot.Active {
|
||||||
pilot, err := initAutoPilot(server, cfg.Autopilot)
|
pilot, err := initAutoPilot(server, cfg.Autopilot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -631,21 +625,12 @@ func lndMain() error {
|
|||||||
err)
|
err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer pilot.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
addInterruptHandler(func() {
|
|
||||||
rpcServer.Stop()
|
|
||||||
fundingMgr.Stop()
|
|
||||||
if pilot != nil {
|
|
||||||
pilot.Stop()
|
|
||||||
}
|
|
||||||
server.Stop()
|
|
||||||
})
|
|
||||||
|
|
||||||
// Wait for shutdown signal from either a graceful server stop or from
|
// Wait for shutdown signal from either a graceful server stop or from
|
||||||
// the interrupt handler.
|
// the interrupt handler.
|
||||||
<-shutdownChannel
|
<-signal.ShutdownChannel()
|
||||||
ltndLog.Info("Shutdown complete")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1036,7 +1021,7 @@ func waitForWalletPassword(grpcEndpoints, restEndpoints []net.Addr,
|
|||||||
// Don't leave the file open in case the new wallet
|
// Don't leave the file open in case the new wallet
|
||||||
// could not be created for whatever reason.
|
// could not be created for whatever reason.
|
||||||
if err := loader.UnloadWallet(); err != nil {
|
if err := loader.UnloadWallet(); err != nil {
|
||||||
ltndLog.Errorf("Could not unload new " +
|
ltndLog.Errorf("Could not unload new "+
|
||||||
"wallet: %v", err)
|
"wallet: %v", err)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -1061,7 +1046,7 @@ func waitForWalletPassword(grpcEndpoints, restEndpoints []net.Addr,
|
|||||||
}
|
}
|
||||||
return walletInitParams, nil
|
return walletInitParams, nil
|
||||||
|
|
||||||
case <-shutdownChannel:
|
case <-signal.ShutdownChannel():
|
||||||
return nil, fmt.Errorf("shutting down")
|
return nil, fmt.Errorf("shutting down")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
log.go
2
log.go
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
"github.com/lightningnetwork/lnd/routing"
|
||||||
|
"github.com/lightningnetwork/lnd/signal"
|
||||||
"github.com/roasbeef/btcd/connmgr"
|
"github.com/roasbeef/btcd/connmgr"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -89,6 +90,7 @@ func init() {
|
|||||||
autopilot.UseLogger(atplLog)
|
autopilot.UseLogger(atplLog)
|
||||||
contractcourt.UseLogger(cnctLog)
|
contractcourt.UseLogger(cnctLog)
|
||||||
sphinx.UseLogger(sphxLog)
|
sphinx.UseLogger(sphxLog)
|
||||||
|
signal.UseLogger(ltndLog)
|
||||||
}
|
}
|
||||||
|
|
||||||
// subsystemLoggers maps each subsystem identifier to its associated logger.
|
// subsystemLoggers maps each subsystem identifier to its associated logger.
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
"github.com/lightningnetwork/lnd/routing"
|
||||||
|
"github.com/lightningnetwork/lnd/signal"
|
||||||
"github.com/lightningnetwork/lnd/zpay32"
|
"github.com/lightningnetwork/lnd/zpay32"
|
||||||
"github.com/roasbeef/btcd/blockchain"
|
"github.com/roasbeef/btcd/blockchain"
|
||||||
"github.com/roasbeef/btcd/btcec"
|
"github.com/roasbeef/btcd/btcec"
|
||||||
@ -3416,7 +3417,7 @@ func (r *rpcServer) GetNetworkInfo(ctx context.Context,
|
|||||||
func (r *rpcServer) StopDaemon(ctx context.Context,
|
func (r *rpcServer) StopDaemon(ctx context.Context,
|
||||||
_ *lnrpc.StopRequest) (*lnrpc.StopResponse, error) {
|
_ *lnrpc.StopRequest) (*lnrpc.StopResponse, error) {
|
||||||
|
|
||||||
shutdownRequestChannel <- struct{}{}
|
signal.RequestShutdown()
|
||||||
return &lnrpc.StopResponse{}, nil
|
return &lnrpc.StopResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
96
signal.go
96
signal.go
@ -1,96 +0,0 @@
|
|||||||
// Copyright (c) 2013-2017 The btcsuite developers
|
|
||||||
// Copyright (c) 2015-2016 The Decred developers
|
|
||||||
// Heavily inspired by https://github.com/btcsuite/btcd/blob/master/signal.go
|
|
||||||
// Copyright (C) 2015-2017 The Lightning Network Developers
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
)
|
|
||||||
|
|
||||||
// interruptChannel is used to receive SIGINT (Ctrl+C) signals.
|
|
||||||
var interruptChannel chan os.Signal
|
|
||||||
|
|
||||||
// shutdownRequestChannel is used to request the daemon to shutdown gracefully,
|
|
||||||
// similar to when receiving SIGINT.
|
|
||||||
var shutdownRequestChannel = make(chan struct{})
|
|
||||||
|
|
||||||
// addHandlerChannel is used to add an interrupt handler to the list of handlers
|
|
||||||
// to be invoked on SIGINT (Ctrl+C) signals and shutdown.
|
|
||||||
var addHandlerChannel = make(chan func())
|
|
||||||
|
|
||||||
// mainInterruptHandler listens for SIGINT (Ctrl+C) signals on the
|
|
||||||
// interruptChannel and shutdown requests on the shutdownRequestChannel, and
|
|
||||||
// invokes the registered interruptCallbacks accordingly. It also listens for
|
|
||||||
// callback registration.
|
|
||||||
// It must be run as a goroutine.
|
|
||||||
func mainInterruptHandler() {
|
|
||||||
// interruptCallbacks is a list of callbacks to invoke when a
|
|
||||||
// SIGINT (Ctrl+C) or a shutdown request is received.
|
|
||||||
var interruptCallbacks []func()
|
|
||||||
|
|
||||||
// isShutdown is a flag which is used to indicate whether or not
|
|
||||||
// the shutdown signal has already been received and hence any future
|
|
||||||
// attempts to add a new interrupt handler should invoke them
|
|
||||||
// immediately.
|
|
||||||
var isShutdown bool
|
|
||||||
|
|
||||||
// shutdown invokes the registered interrupt handlers, then signals the
|
|
||||||
// shutdownChannel.
|
|
||||||
shutdown := func() {
|
|
||||||
// Ignore more than one shutdown signal.
|
|
||||||
if isShutdown {
|
|
||||||
ltndLog.Infof("Already shutting down...")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
isShutdown = true
|
|
||||||
ltndLog.Infof("Shutting down...")
|
|
||||||
|
|
||||||
// Execute the interrupt callbacks in FIFO order.
|
|
||||||
for _, callback := range interruptCallbacks {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal the main goroutine to shutdown.
|
|
||||||
go func() {
|
|
||||||
shutdownChannel <- struct{}{}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-interruptChannel:
|
|
||||||
ltndLog.Infof("Received SIGINT (Ctrl+C).")
|
|
||||||
shutdown()
|
|
||||||
|
|
||||||
case <-shutdownRequestChannel:
|
|
||||||
ltndLog.Infof("Received shutdown request.")
|
|
||||||
shutdown()
|
|
||||||
|
|
||||||
case handler := <-addHandlerChannel:
|
|
||||||
// The shutdown signal has already been received, so
|
|
||||||
// just invoke any new handlers immediately.
|
|
||||||
if isShutdown {
|
|
||||||
handler()
|
|
||||||
}
|
|
||||||
|
|
||||||
interruptCallbacks = append(interruptCallbacks, handler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// addInterruptHandler adds a handler to call when a SIGINT (Ctrl+C) or a
|
|
||||||
// shutdown request is received.
|
|
||||||
func addInterruptHandler(handler func()) {
|
|
||||||
// Create the channel and start the main interrupt handler which invokes
|
|
||||||
// all other callbacks and exits if not already done.
|
|
||||||
if interruptChannel == nil {
|
|
||||||
interruptChannel = make(chan os.Signal, 1)
|
|
||||||
signal.Notify(interruptChannel, os.Interrupt)
|
|
||||||
go mainInterruptHandler()
|
|
||||||
}
|
|
||||||
|
|
||||||
addHandlerChannel <- handler
|
|
||||||
}
|
|
26
signal/log.go
Normal file
26
signal/log.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package signal
|
||||||
|
|
||||||
|
import "github.com/btcsuite/btclog"
|
||||||
|
|
||||||
|
// log is a logger that is initialized with no output filters. This
|
||||||
|
// means the package will not perform any logging by default until the caller
|
||||||
|
// requests it.
|
||||||
|
var log btclog.Logger
|
||||||
|
|
||||||
|
// The default amount of logging is none.
|
||||||
|
func init() {
|
||||||
|
DisableLog()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableLog disables all library log output. Logging output is disabled
|
||||||
|
// by default until UseLogger is called.
|
||||||
|
func DisableLog() {
|
||||||
|
log = btclog.Disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// UseLogger uses a specified Logger to output package logging info.
|
||||||
|
// This should be used in preference to SetLogWriter if the caller is also
|
||||||
|
// using btclog.
|
||||||
|
func UseLogger(logger btclog.Logger) {
|
||||||
|
log = logger
|
||||||
|
}
|
101
signal/signal.go
Normal file
101
signal/signal.go
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
// Copyright (c) 2013-2017 The btcsuite developers
|
||||||
|
// Copyright (c) 2015-2016 The Decred developers
|
||||||
|
// Heavily inspired by https://github.com/btcsuite/btcd/blob/master/signal.go
|
||||||
|
// Copyright (C) 2015-2017 The Lightning Network Developers
|
||||||
|
|
||||||
|
package signal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// interruptChannel is used to receive SIGINT (Ctrl+C) signals.
|
||||||
|
interruptChannel = make(chan os.Signal, 1)
|
||||||
|
|
||||||
|
// shutdownRequestChannel is used to request the daemon to shutdown
|
||||||
|
// gracefully, similar to when receiving SIGINT.
|
||||||
|
shutdownRequestChannel = make(chan struct{})
|
||||||
|
|
||||||
|
// quit is closed when instructing the main interrupt handler to exit.
|
||||||
|
quit = make(chan struct{})
|
||||||
|
|
||||||
|
// shutdownChannel is closed once the main interrupt handler exits.
|
||||||
|
shutdownChannel = make(chan struct{})
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
signal.Notify(interruptChannel, os.Interrupt)
|
||||||
|
go mainInterruptHandler()
|
||||||
|
}
|
||||||
|
|
||||||
|
// mainInterruptHandler listens for SIGINT (Ctrl+C) signals on the
|
||||||
|
// interruptChannel and shutdown requests on the shutdownRequestChannel, and
|
||||||
|
// invokes the registered interruptCallbacks accordingly. It also listens for
|
||||||
|
// callback registration.
|
||||||
|
// It must be run as a goroutine.
|
||||||
|
func mainInterruptHandler() {
|
||||||
|
// isShutdown is a flag which is used to indicate whether or not
|
||||||
|
// the shutdown signal has already been received and hence any future
|
||||||
|
// attempts to add a new interrupt handler should invoke them
|
||||||
|
// immediately.
|
||||||
|
var isShutdown bool
|
||||||
|
|
||||||
|
// shutdown invokes the registered interrupt handlers, then signals the
|
||||||
|
// shutdownChannel.
|
||||||
|
shutdown := func() {
|
||||||
|
// Ignore more than one shutdown signal.
|
||||||
|
if isShutdown {
|
||||||
|
log.Infof("Already shutting down...")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isShutdown = true
|
||||||
|
log.Infof("Shutting down...")
|
||||||
|
|
||||||
|
// Signal the main interrupt handler to exit, and stop accept
|
||||||
|
// post-facto requests.
|
||||||
|
close(quit)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-interruptChannel:
|
||||||
|
log.Infof("Received SIGINT (Ctrl+C).")
|
||||||
|
shutdown()
|
||||||
|
|
||||||
|
case <-shutdownRequestChannel:
|
||||||
|
log.Infof("Received shutdown request.")
|
||||||
|
shutdown()
|
||||||
|
|
||||||
|
case <-quit:
|
||||||
|
log.Infof("Gracefully shutting down.")
|
||||||
|
close(shutdownChannel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alive returns true if the main interrupt handler has not been killed.
|
||||||
|
func Alive() bool {
|
||||||
|
select {
|
||||||
|
case <-quit:
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestShutdown initiates a graceful shutdown from the application.
|
||||||
|
func RequestShutdown() {
|
||||||
|
select {
|
||||||
|
case shutdownRequestChannel <- struct{}{}:
|
||||||
|
case <-quit:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShutdownChannel returns the channel that will be closed once the main
|
||||||
|
// interrupt handler has exited.
|
||||||
|
func ShutdownChannel() <-chan struct{} {
|
||||||
|
return shutdownChannel
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user