kaspad/util/panics/panics.go
Ori Newman a10320ad7b [NOD-696] Handle panics on time.AfterFunc (#600)
* [NOD-696] Handle panics on time.AfterFunc

* [NOD-696] Fix comment

* [NOD-696] Rename afterFunc->spawnAfter
2020-01-27 11:12:23 +02:00

71 lines
2.2 KiB
Go

package panics
import (
"github.com/kaspanet/kaspad/logs"
"github.com/kaspanet/kaspad/signal"
"runtime/debug"
"time"
)
// HandlePanic recovers panics, log them, runs an optional panicHandler,
// and then initiates a clean shutdown.
func HandlePanic(log logs.Logger, goroutineStackTrace []byte, panicHandler func()) {
if err := recover(); err != nil {
log.Criticalf("Fatal error: %+v", err)
if goroutineStackTrace != nil {
log.Criticalf("goroutine stack trace: %s", goroutineStackTrace)
}
log.Criticalf("Stack trace: %s", debug.Stack())
if panicHandler != nil {
panicHandler()
}
signal.PanicShutdownChannel <- struct{}{}
}
}
// GoroutineWrapperFunc returns a goroutine wrapper function that handles panics and writes them to the log.
func GoroutineWrapperFunc(log logs.Logger) func(func()) {
return func(f func()) {
stackTrace := debug.Stack()
go func() {
defer HandlePanic(log, stackTrace, nil)
f()
}()
}
}
// GoroutineWrapperFuncWithPanicHandler returns a goroutine wrapper function that handles panics,
// writes 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()
}()
}
}
// 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()
})
}
}