mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-09 15:46:43 +00:00
[NOD-487] Implement a mechanism to gracefully shut down after a panic (#512)
* [NOD-487] Implement a mechanism to gracefully shut down after a panic. * [NOD-487] Fixed bad log. * [NOD-487] Removed unused import. * [NOD-487] Convert panic handlers from anonymous functions to methods.
This commit is contained in:
parent
7b6ed9a778
commit
9adb105e37
@ -724,7 +724,11 @@ func (a *AddrManager) Start() {
|
|||||||
|
|
||||||
// Start the address ticker to save addresses periodically.
|
// Start the address ticker to save addresses periodically.
|
||||||
a.wg.Add(1)
|
a.wg.Add(1)
|
||||||
spawn(a.addressHandler)
|
spawn(a.addressHandler, a.handlePanic)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AddrManager) handlePanic() {
|
||||||
|
atomic.AddInt32(&a.shutdown, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop gracefully shuts down the address manager by stopping the main handler.
|
// Stop gracefully shuts down the address manager by stopping the main handler.
|
||||||
|
@ -10,4 +10,4 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var log, _ = logger.Get(logger.SubsystemTags.ADXR)
|
var log, _ = logger.Get(logger.SubsystemTags.ADXR)
|
||||||
var spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
var spawn = panics.GoroutineWrapperFuncWithPanicHandler(log)
|
||||||
|
@ -5,5 +5,5 @@ import "github.com/daglabs/btcd/apiserver/logger"
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
log = logger.Logger("DTBS")
|
log = logger.Logger("DTBS")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
log = logger.BackendLog.Logger("RPCC")
|
log = logger.BackendLog.Logger("RPCC")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rpcclient.UseLogger(log, logger.BackendLog)
|
rpcclient.UseLogger(log)
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,5 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
log = logger.Logger("APIS")
|
log = logger.Logger("APIS")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/daglabs/btcd/apiserver/database"
|
"github.com/daglabs/btcd/apiserver/database"
|
||||||
"github.com/daglabs/btcd/apiserver/jsonrpc"
|
"github.com/daglabs/btcd/apiserver/jsonrpc"
|
||||||
"github.com/daglabs/btcd/apiserver/server"
|
"github.com/daglabs/btcd/apiserver/server"
|
||||||
"github.com/daglabs/btcd/logger"
|
|
||||||
"github.com/daglabs/btcd/signal"
|
"github.com/daglabs/btcd/signal"
|
||||||
"github.com/daglabs/btcd/util/panics"
|
"github.com/daglabs/btcd/util/panics"
|
||||||
_ "github.com/golang-migrate/migrate/v4/database/mysql"
|
_ "github.com/golang-migrate/migrate/v4/database/mysql"
|
||||||
@ -19,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
defer panics.HandlePanic(log, logger.BackendLog, nil)
|
defer panics.HandlePanic(log, nil, nil)
|
||||||
|
|
||||||
err := config.Parse()
|
err := config.Parse()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -5,5 +5,5 @@ import "github.com/daglabs/btcd/apiserver/logger"
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
log = logger.Logger("MQTT")
|
log = logger.Logger("MQTT")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
@ -5,5 +5,5 @@ import "github.com/daglabs/btcd/apiserver/logger"
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
log = logger.Logger("REST")
|
log = logger.Logger("REST")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
@ -10,4 +10,4 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var log, _ = logger.Get(logger.SubsystemTags.INDX)
|
var log, _ = logger.Get(logger.SubsystemTags.INDX)
|
||||||
var spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
var spawn = panics.GoroutineWrapperFunc(log)
|
||||||
|
@ -10,4 +10,4 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var log, _ = logger.Get(logger.SubsystemTags.BDAG)
|
var log, _ = logger.Get(logger.SubsystemTags.BDAG)
|
||||||
var spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
var spawn = panics.GoroutineWrapperFunc(log)
|
||||||
|
3
btcd.go
3
btcd.go
@ -6,7 +6,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/daglabs/btcd/logger"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
@ -57,7 +56,7 @@ func btcdMain(serverChan chan<- *server.Server) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cfg = config.ActiveConfig()
|
cfg = config.ActiveConfig()
|
||||||
defer panics.HandlePanic(btcdLog, logger.BackendLog, nil)
|
defer panics.HandlePanic(btcdLog, nil, nil)
|
||||||
|
|
||||||
// Get a channel that will be closed when a shutdown signal has been
|
// Get a channel that will be closed when a shutdown signal has been
|
||||||
// triggered either from an OS signal such as SIGINT (Ctrl+C) or from
|
// triggered either from an OS signal such as SIGINT (Ctrl+C) or from
|
||||||
|
@ -72,7 +72,7 @@ func realMain() error {
|
|||||||
backendLogger := logs.NewBackend()
|
backendLogger := logs.NewBackend()
|
||||||
defer os.Stdout.Sync()
|
defer os.Stdout.Sync()
|
||||||
log = backendLogger.Logger("MAIN")
|
log = backendLogger.Logger("MAIN")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, backendLogger)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
|
|
||||||
// Load the block database.
|
// Load the block database.
|
||||||
db, err := loadBlockDB()
|
db, err := loadBlockDB()
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
backendLog = logs.NewBackend()
|
backendLog = logs.NewBackend()
|
||||||
log = backendLog.Logger("TXGN")
|
log = backendLog.Logger("TXGN")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, backendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
|
||||||
func initLog(logFile, errLogFile string) {
|
func initLog(logFile, errLogFile string) {
|
||||||
|
@ -23,7 +23,7 @@ func privateKeyToP2pkhAddress(key *btcec.PrivateKey, net *dagconfig.Params) (uti
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
defer panics.HandlePanic(log, backendLog, nil)
|
defer panics.HandlePanic(log, nil, nil)
|
||||||
|
|
||||||
cfg, err := parseConfig()
|
cfg, err := parseConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -247,7 +247,7 @@ func (cm *ConnManager) handleFailedConn(c *ConnReq, err error) {
|
|||||||
cm.NewConnReq()
|
cm.NewConnReq()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
spawn(cm.NewConnReq)
|
spawn(cm.NewConnReq, cm.handlePanic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -584,7 +584,7 @@ func (cm *ConnManager) Start() {
|
|||||||
|
|
||||||
log.Trace("Connection manager started")
|
log.Trace("Connection manager started")
|
||||||
cm.wg.Add(1)
|
cm.wg.Add(1)
|
||||||
spawn(cm.connHandler)
|
spawn(cm.connHandler, cm.handlePanic)
|
||||||
|
|
||||||
// Start all the listeners so long as the caller requested them and
|
// Start all the listeners so long as the caller requested them and
|
||||||
// provided a callback to be invoked when connections are accepted.
|
// provided a callback to be invoked when connections are accepted.
|
||||||
@ -596,7 +596,7 @@ func (cm *ConnManager) Start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := atomic.LoadUint64(&cm.connReqCount); i < uint64(cm.cfg.TargetOutbound); i++ {
|
for i := atomic.LoadUint64(&cm.connReqCount); i < uint64(cm.cfg.TargetOutbound); i++ {
|
||||||
spawn(cm.NewConnReq)
|
spawn(cm.NewConnReq, cm.handlePanic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,6 +605,10 @@ func (cm *ConnManager) Wait() {
|
|||||||
cm.wg.Wait()
|
cm.wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cm *ConnManager) handlePanic() {
|
||||||
|
atomic.AddInt32(&cm.stop, 1)
|
||||||
|
}
|
||||||
|
|
||||||
// Stop gracefully shuts down the connection manager.
|
// Stop gracefully shuts down the connection manager.
|
||||||
func (cm *ConnManager) Stop() {
|
func (cm *ConnManager) Stop() {
|
||||||
if atomic.AddInt32(&cm.stop, 1) != 1 {
|
if atomic.AddInt32(&cm.stop, 1) != 1 {
|
||||||
|
@ -10,4 +10,4 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var log, _ = logger.Get(logger.SubsystemTags.CMGR)
|
var log, _ = logger.Get(logger.SubsystemTags.CMGR)
|
||||||
var spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
var spawn = panics.GoroutineWrapperFuncWithPanicHandler(log)
|
||||||
|
@ -67,7 +67,7 @@ func realMain() error {
|
|||||||
backendLogger := logs.NewBackend()
|
backendLogger := logs.NewBackend()
|
||||||
defer os.Stdout.Sync()
|
defer os.Stdout.Sync()
|
||||||
log = backendLogger.Logger("MAIN")
|
log = backendLogger.Logger("MAIN")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, backendLogger)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
dbLog, _ := logger.Get(logger.SubsystemTags.BCDB)
|
dbLog, _ := logger.Get(logger.SubsystemTags.BCDB)
|
||||||
dbLog.SetLevel(logs.LevelDebug)
|
dbLog.SetLevel(logs.LevelDebug)
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ func creep() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
defer panics.HandlePanic(log, backendLog, nil)
|
defer panics.HandlePanic(log, nil, nil)
|
||||||
cfg, err := loadConfig()
|
cfg, err := loadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "loadConfig: %v\n", err)
|
fmt.Fprintf(os.Stderr, "loadConfig: %v\n", err)
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
backendLog = logs.NewBackend()
|
backendLog = logs.NewBackend()
|
||||||
log = backendLog.Logger("SEED")
|
log = backendLog.Logger("SEED")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, backendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
|
||||||
func initLog(logFile, errLogFile string) {
|
func initLog(logFile, errLogFile string) {
|
||||||
|
@ -5,5 +5,5 @@ import "github.com/daglabs/btcd/apiserver/logger"
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
log = logger.BackendLog.Logger("DTBS")
|
log = logger.BackendLog.Logger("DTBS")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
@ -7,5 +7,5 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
log = logger.BackendLog.Logger("FAUC")
|
log = logger.BackendLog.Logger("FAUC")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/daglabs/btcd/logger"
|
|
||||||
"github.com/daglabs/btcd/signal"
|
"github.com/daglabs/btcd/signal"
|
||||||
"github.com/daglabs/btcd/util/panics"
|
"github.com/daglabs/btcd/util/panics"
|
||||||
_ "github.com/golang-migrate/migrate/v4/database/mysql"
|
_ "github.com/golang-migrate/migrate/v4/database/mysql"
|
||||||
@ -27,7 +26,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
defer panics.HandlePanic(log, logger.BackendLog, nil)
|
defer panics.HandlePanic(log, nil, nil)
|
||||||
|
|
||||||
err := config.Parse()
|
err := config.Parse()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -5,5 +5,5 @@ import "github.com/daglabs/btcd/apiserver/logger"
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
log = logger.BackendLog.Logger("UTIL")
|
log = logger.BackendLog.Logger("UTIL")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
2
log.go
2
log.go
@ -11,5 +11,5 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var btcdLog, _ = logger.Get(logger.SubsystemTags.BTCD)
|
var btcdLog, _ = logger.Get(logger.SubsystemTags.BTCD)
|
||||||
var spawn = panics.GoroutineWrapperFunc(btcdLog, logger.BackendLog)
|
var spawn = panics.GoroutineWrapperFunc(btcdLog)
|
||||||
var srvrLog, _ = logger.Get(logger.SubsystemTags.SRVR)
|
var srvrLog, _ = logger.Get(logger.SubsystemTags.SRVR)
|
||||||
|
@ -10,4 +10,4 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var log, _ = logger.Get(logger.SubsystemTags.MINR)
|
var log, _ = logger.Get(logger.SubsystemTags.MINR)
|
||||||
var spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
var spawn = panics.GoroutineWrapperFunc(log)
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
backendLog = logs.NewBackend()
|
backendLog = logs.NewBackend()
|
||||||
log = backendLog.Logger("MNSM")
|
log = backendLog.Logger("MNSM")
|
||||||
spawn = panics.GoroutineWrapperFunc(log, backendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
|
||||||
func initLog(logFile, errLogFile string) {
|
func initLog(logFile, errLogFile string) {
|
||||||
@ -30,5 +30,5 @@ func initLog(logFile, errLogFile string) {
|
|||||||
func enableRPCLogging() {
|
func enableRPCLogging() {
|
||||||
rpclog := backendLog.Logger("RPCC")
|
rpclog := backendLog.Logger("RPCC")
|
||||||
rpclog.SetLevel(logs.LevelTrace)
|
rpclog.SetLevel(logs.LevelTrace)
|
||||||
rpcclient.UseLogger(rpclog, backendLog)
|
rpcclient.UseLogger(rpclog)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
defer panics.HandlePanic(log, backendLog, nil)
|
defer panics.HandlePanic(log, nil, nil)
|
||||||
cfg, err := parseConfig()
|
cfg, err := parseConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error parsing command-line arguments: %s", err)
|
fmt.Fprintf(os.Stderr, "Error parsing command-line arguments: %s", err)
|
||||||
|
@ -10,4 +10,4 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var log, _ = logger.Get(logger.SubsystemTags.SYNC)
|
var log, _ = logger.Get(logger.SubsystemTags.SYNC)
|
||||||
var spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
var spawn = panics.GoroutineWrapperFuncWithPanicHandler(log)
|
||||||
|
@ -622,7 +622,7 @@ func (sm *SyncManager) handleBlockMsg(bmsg *blockMsg) {
|
|||||||
if delay != 0 {
|
if delay != 0 {
|
||||||
spawn(func() {
|
spawn(func() {
|
||||||
sm.QueueBlock(bmsg.block, bmsg.peer, true, make(chan struct{}))
|
sm.QueueBlock(bmsg.block, bmsg.peer, true, make(chan struct{}))
|
||||||
})
|
}, sm.handlePanic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request the parents for the orphan block from the peer that sent it.
|
// Request the parents for the orphan block from the peer that sent it.
|
||||||
@ -1289,7 +1289,7 @@ func (sm *SyncManager) handleBlockDAGNotification(notification *blockdag.Notific
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("HandleNewBlock failed to handle block %s", block.Hash()))
|
panic(fmt.Sprintf("HandleNewBlock failed to handle block %s", block.Hash()))
|
||||||
}
|
}
|
||||||
})
|
}, sm.handlePanic)
|
||||||
|
|
||||||
// Relay if we are current and the block was not just now unorphaned.
|
// Relay if we are current and the block was not just now unorphaned.
|
||||||
// Otherwise peers that are current should already know about it
|
// Otherwise peers that are current should already know about it
|
||||||
@ -1393,7 +1393,11 @@ func (sm *SyncManager) Start() {
|
|||||||
|
|
||||||
log.Trace("Starting sync manager")
|
log.Trace("Starting sync manager")
|
||||||
sm.wg.Add(1)
|
sm.wg.Add(1)
|
||||||
spawn(sm.blockHandler)
|
spawn(sm.blockHandler, sm.handlePanic)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *SyncManager) handlePanic() {
|
||||||
|
atomic.AddInt32(&sm.shutdown, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop gracefully shuts down the sync manager by stopping all asynchronous
|
// Stop gracefully shuts down the sync manager by stopping all asynchronous
|
||||||
|
@ -22,7 +22,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var log, _ = logger.Get(logger.SubsystemTags.PEER)
|
var log, _ = logger.Get(logger.SubsystemTags.PEER)
|
||||||
var spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
var spawn = panics.GoroutineWrapperFunc(log)
|
||||||
|
|
||||||
// LogClosure is a closure that can be printed with %s to be used to
|
// LogClosure is a closure that can be printed with %s to be used to
|
||||||
// generate expensive-to-create data for a detailed log level and avoid doing
|
// generate expensive-to-create data for a detailed log level and avoid doing
|
||||||
|
@ -24,13 +24,13 @@ func init() {
|
|||||||
// by default until UseLogger is called.
|
// by default until UseLogger is called.
|
||||||
func DisableLog() {
|
func DisableLog() {
|
||||||
log = logs.Disabled
|
log = logs.Disabled
|
||||||
spawn = panics.GoroutineWrapperFunc(log, nil)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseLogger uses a specified Logger to output package logging info.
|
// UseLogger uses a specified Logger to output package logging info.
|
||||||
func UseLogger(logger logs.Logger, backendLog *logs.Backend) {
|
func UseLogger(logger logs.Logger) {
|
||||||
log = logger
|
log = logger
|
||||||
spawn = panics.GoroutineWrapperFunc(log, backendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogClosure is a closure that can be printed with %s to be used to
|
// LogClosure is a closure that can be printed with %s to be used to
|
||||||
|
@ -11,5 +11,5 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
log, _ = logger.Get(logger.SubsystemTags.SRVR)
|
log, _ = logger.Get(logger.SubsystemTags.SRVR)
|
||||||
spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
srvrLog, _ = logger.Get(logger.SubsystemTags.SRVR)
|
srvrLog, _ = logger.Get(logger.SubsystemTags.SRVR)
|
||||||
peerLog, _ = logger.Get(logger.SubsystemTags.PEER)
|
peerLog, _ = logger.Get(logger.SubsystemTags.PEER)
|
||||||
spawn = panics.GoroutineWrapperFunc(peerLog, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(peerLog)
|
||||||
|
|
||||||
txmpLog, _ = logger.Get(logger.SubsystemTags.TXMP)
|
txmpLog, _ = logger.Get(logger.SubsystemTags.TXMP)
|
||||||
indxLog, _ = logger.Get(logger.SubsystemTags.INDX)
|
indxLog, _ = logger.Get(logger.SubsystemTags.INDX)
|
||||||
|
@ -11,5 +11,5 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
log, _ = logger.Get(logger.SubsystemTags.RPCS)
|
log, _ = logger.Get(logger.SubsystemTags.RPCS)
|
||||||
spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
@ -13,6 +13,10 @@ import (
|
|||||||
// subsystems using the same code paths as when an interrupt signal is received.
|
// subsystems using the same code paths as when an interrupt signal is received.
|
||||||
var ShutdownRequestChannel = make(chan struct{})
|
var ShutdownRequestChannel = make(chan struct{})
|
||||||
|
|
||||||
|
// PanicShutdownChannel is used to initiate shutdown when any thread
|
||||||
|
// panics using the same code paths as when an interrupt signal is received.
|
||||||
|
var PanicShutdownChannel = make(chan struct{})
|
||||||
|
|
||||||
// interruptSignals defines the default signals to catch in order to do a proper
|
// interruptSignals defines the default signals to catch in order to do a proper
|
||||||
// shutdown. This may be modified during init depending on the platform.
|
// shutdown. This may be modified during init depending on the platform.
|
||||||
var interruptSignals = []os.Signal{os.Interrupt}
|
var interruptSignals = []os.Signal{os.Interrupt}
|
||||||
@ -30,11 +34,14 @@ func InterruptListener() <-chan struct{} {
|
|||||||
// channel to notify the caller.
|
// channel to notify the caller.
|
||||||
select {
|
select {
|
||||||
case sig := <-interruptChannel:
|
case sig := <-interruptChannel:
|
||||||
btcdLog.Infof("Received signal (%s). Shutting down...",
|
btcdLog.Infof("Received signal (%s). Shutting down...",
|
||||||
sig)
|
sig)
|
||||||
|
|
||||||
case <-ShutdownRequestChannel:
|
case <-ShutdownRequestChannel:
|
||||||
btcdLog.Info("Shutdown requested. Shutting down...")
|
btcdLog.Info("Shutdown requested. Shutting down...")
|
||||||
|
|
||||||
|
case <-PanicShutdownChannel:
|
||||||
|
btcdLog.Info("Panic occurred. Shutting down...")
|
||||||
}
|
}
|
||||||
close(c)
|
close(c)
|
||||||
|
|
||||||
@ -44,12 +51,17 @@ func InterruptListener() <-chan struct{} {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case sig := <-interruptChannel:
|
case sig := <-interruptChannel:
|
||||||
btcdLog.Infof("Received signal (%s). Already "+
|
btcdLog.Infof("Received signal (%s). Already "+
|
||||||
"shutting down...", sig)
|
"shutting down...", sig)
|
||||||
|
|
||||||
case <-ShutdownRequestChannel:
|
case <-ShutdownRequestChannel:
|
||||||
btcdLog.Info("Shutdown requested. Already " +
|
btcdLog.Info("Shutdown requested. Already " +
|
||||||
"shutting down...")
|
"shutting down...")
|
||||||
|
|
||||||
|
case <-PanicShutdownChannel:
|
||||||
|
btcdLog.Info("Panic occurred while shutting down. " +
|
||||||
|
"Forcing shut down...")
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -11,5 +11,5 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
log, _ = logger.Get(logger.SubsystemTags.UTIL)
|
log, _ = logger.Get(logger.SubsystemTags.UTIL)
|
||||||
spawn = panics.GoroutineWrapperFunc(log, logger.BackendLog)
|
spawn = panics.GoroutineWrapperFunc(log)
|
||||||
)
|
)
|
||||||
|
@ -2,31 +2,44 @@ package panics
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/daglabs/btcd/logs"
|
"github.com/daglabs/btcd/logs"
|
||||||
"os"
|
"github.com/daglabs/btcd/signal"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandlePanic recovers panics, log them, and then exits the process.
|
// HandlePanic recovers panics, log them, runs an optional panicHandler,
|
||||||
func HandlePanic(log logs.Logger, backendLog *logs.Backend, goroutineStackTrace []byte) {
|
// and then initiates a clean shutdown.
|
||||||
|
func HandlePanic(log logs.Logger, goroutineStackTrace []byte, panicHandler func()) {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
log.Criticalf("Fatal error: %+v", err)
|
log.Criticalf("Fatal error: %+v", err)
|
||||||
if goroutineStackTrace != nil {
|
if goroutineStackTrace != nil {
|
||||||
log.Criticalf("goroutine stack trance: %s", goroutineStackTrace)
|
log.Criticalf("goroutine stack trace: %s", goroutineStackTrace)
|
||||||
}
|
}
|
||||||
log.Criticalf("Stack trace: %s", debug.Stack())
|
log.Criticalf("Stack trace: %s", debug.Stack())
|
||||||
if backendLog != nil {
|
if panicHandler != nil {
|
||||||
backendLog.Close()
|
panicHandler()
|
||||||
}
|
}
|
||||||
os.Exit(1)
|
signal.PanicShutdownChannel <- struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GoroutineWrapperFunc returns a goroutine wrapper function that handles panics and write them to the log.
|
// GoroutineWrapperFunc returns a goroutine wrapper function that handles panics and write them to the log.
|
||||||
func GoroutineWrapperFunc(log logs.Logger, backendLog *logs.Backend) func(func()) {
|
func GoroutineWrapperFunc(log logs.Logger) func(func()) {
|
||||||
return func(f func()) {
|
return func(f func()) {
|
||||||
stackTrace := debug.Stack()
|
stackTrace := debug.Stack()
|
||||||
go func() {
|
go func() {
|
||||||
defer HandlePanic(log, backendLog, stackTrace)
|
defer HandlePanic(log, stackTrace, nil)
|
||||||
|
f()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoroutineWrapperFuncWithPanicHandler returns a goroutine wrapper function that handles panics,
|
||||||
|
// write them to the log, and executes a handler function for panics.
|
||||||
|
func GoroutineWrapperFuncWithPanicHandler(log logs.Logger) func(func(), func()) {
|
||||||
|
return func(f func(), panicHandler func()) {
|
||||||
|
stackTrace := debug.Stack()
|
||||||
|
go func() {
|
||||||
|
defer HandlePanic(log, stackTrace, panicHandler)
|
||||||
f()
|
f()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user