[NOD-696] Handle panics on time.AfterFunc (#600)

* [NOD-696] Handle panics on time.AfterFunc

* [NOD-696] Fix comment

* [NOD-696] Rename afterFunc->spawnAfter
This commit is contained in:
Ori Newman 2020-01-27 11:12:23 +02:00 committed by Svarog
parent fd2bbf3557
commit a10320ad7b
5 changed files with 32 additions and 8 deletions

View File

@ -232,9 +232,9 @@ func (cm *ConnManager) handleFailedConn(c *ConnReq, err error) {
if shouldWriteLog { if shouldWriteLog {
log.Debugf("Retrying further connections to %s every %s", c, d) log.Debugf("Retrying further connections to %s every %s", c, d)
} }
time.AfterFunc(d, func() { spawnAfter(d, func() {
cm.Connect(c) cm.Connect(c)
}) }, nil)
} else if cm.cfg.GetNewAddress != nil { } else if cm.cfg.GetNewAddress != nil {
cm.failedAttempts++ cm.failedAttempts++
if cm.failedAttempts >= maxFailedAttempts { if cm.failedAttempts >= maxFailedAttempts {
@ -243,9 +243,7 @@ func (cm *ConnManager) handleFailedConn(c *ConnReq, err error) {
"-- retrying further connections every %s", maxFailedAttempts, "-- retrying further connections every %s", maxFailedAttempts,
cm.cfg.RetryDuration) cm.cfg.RetryDuration)
} }
time.AfterFunc(cm.cfg.RetryDuration, func() { spawnAfter(cm.cfg.RetryDuration, cm.NewConnReq, cm.handlePanic)
cm.NewConnReq()
})
} else { } else {
spawn(cm.NewConnReq, cm.handlePanic) spawn(cm.NewConnReq, cm.handlePanic)
} }

View File

@ -11,3 +11,4 @@ import (
var log, _ = logger.Get(logger.SubsystemTags.CMGR) var log, _ = logger.Get(logger.SubsystemTags.CMGR)
var spawn = panics.GoroutineWrapperFuncWithPanicHandler(log) var spawn = panics.GoroutineWrapperFuncWithPanicHandler(log)
var spawnAfter = panics.AfterFuncWrapperFuncWithPanicHandler(log)

View File

@ -23,6 +23,7 @@ const (
var log, _ = logger.Get(logger.SubsystemTags.PEER) var log, _ = logger.Get(logger.SubsystemTags.PEER)
var spawn = panics.GoroutineWrapperFunc(log) var spawn = panics.GoroutineWrapperFunc(log)
var spawnAfter = panics.AfterFuncWrapperFunc(log)
// formatLockTime returns a transaction lock time as a human-readable string. // formatLockTime returns a transaction lock time as a human-readable string.
func formatLockTime(lockTime uint64) string { func formatLockTime(lockTime uint64) string {

View File

@ -1346,7 +1346,7 @@ cleanup:
func (p *Peer) inHandler() { func (p *Peer) inHandler() {
// The timer is stopped when a new message is received and reset after it // The timer is stopped when a new message is received and reset after it
// is processed. // is processed.
idleTimer := time.AfterFunc(idleTimeout, func() { idleTimer := spawnAfter(idleTimeout, func() {
log.Warnf("Peer %s no answer for %s -- disconnecting", p, idleTimeout) log.Warnf("Peer %s no answer for %s -- disconnecting", p, idleTimeout)
p.Disconnect() p.Disconnect()
}) })

View File

@ -4,6 +4,7 @@ import (
"github.com/kaspanet/kaspad/logs" "github.com/kaspanet/kaspad/logs"
"github.com/kaspanet/kaspad/signal" "github.com/kaspanet/kaspad/signal"
"runtime/debug" "runtime/debug"
"time"
) )
// HandlePanic recovers panics, log them, runs an optional panicHandler, // HandlePanic recovers panics, log them, runs an optional panicHandler,
@ -22,7 +23,7 @@ func HandlePanic(log logs.Logger, goroutineStackTrace []byte, panicHandler func(
} }
} }
// 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 writes them to the log.
func GoroutineWrapperFunc(log logs.Logger) func(func()) { func GoroutineWrapperFunc(log logs.Logger) func(func()) {
return func(f func()) { return func(f func()) {
stackTrace := debug.Stack() stackTrace := debug.Stack()
@ -34,7 +35,7 @@ func GoroutineWrapperFunc(log logs.Logger) func(func()) {
} }
// GoroutineWrapperFuncWithPanicHandler returns a goroutine wrapper function that handles panics, // GoroutineWrapperFuncWithPanicHandler returns a goroutine wrapper function that handles panics,
// write them to the log, and executes a handler function for panics. // writes them to the log, and executes a handler function for panics.
func GoroutineWrapperFuncWithPanicHandler(log logs.Logger) func(func(), func()) { func GoroutineWrapperFuncWithPanicHandler(log logs.Logger) func(func(), func()) {
return func(f func(), panicHandler func()) { return func(f func(), panicHandler func()) {
stackTrace := debug.Stack() stackTrace := debug.Stack()
@ -44,3 +45,26 @@ func GoroutineWrapperFuncWithPanicHandler(log logs.Logger) func(func(), func())
}() }()
} }
} }
// AfterFuncWrapperFunc returns a time.AfterFunc wrapper function that handles panics.
func AfterFuncWrapperFunc(log logs.Logger) func(d time.Duration, f func()) *time.Timer {
return func(d time.Duration, f func()) *time.Timer {
stackTrace := debug.Stack()
return time.AfterFunc(d, func() {
defer HandlePanic(log, stackTrace, nil)
f()
})
}
}
// AfterFuncWrapperFuncWithPanicHandler returns a time.AfterFunc wrapper function that handles panics,
// writes them to the log, and executes a handler function for panics.
func AfterFuncWrapperFuncWithPanicHandler(log logs.Logger) func(d time.Duration, f func(), panicHandler func()) *time.Timer {
return func(d time.Duration, f func(), panicHandler func()) *time.Timer {
stackTrace := debug.Stack()
return time.AfterFunc(d, func() {
defer HandlePanic(log, stackTrace, panicHandler)
f()
})
}
}