mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-07-06 04:42:31 +00:00

* [NOD-806] After panic, gracefully stop logs, and then exit immediately * [NOD-806] Convert non-kaspad applications to use the new spawn * [NOD-806] Fix disabled log at rpcclient * [NOD-806] Refactor HandlePanic * [NOD-806] Cancel Logger interface * [NOD-806] Remove redundant spawn checks from waitgroup_test.go * [NOD-806] Use caller subsystem when logging panics * [NOD-806] Fix go vet errors
60 lines
1.5 KiB
Go
60 lines
1.5 KiB
Go
package panics
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/kaspanet/kaspad/logs"
|
|
"os"
|
|
"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) {
|
|
err := recover()
|
|
if err == nil {
|
|
return
|
|
}
|
|
|
|
panicHandlerDone := make(chan struct{})
|
|
go func() {
|
|
log.Criticalf("Fatal error: %+v", err)
|
|
if goroutineStackTrace != nil {
|
|
log.Criticalf("Goroutine stack trace: %s", goroutineStackTrace)
|
|
}
|
|
log.Criticalf("Stack trace: %s", debug.Stack())
|
|
log.Backend().Close()
|
|
panicHandlerDone <- struct{}{}
|
|
}()
|
|
|
|
const panicHandlerTimeout = 5 * time.Second
|
|
select {
|
|
case <-time.Tick(panicHandlerTimeout):
|
|
fmt.Fprintln(os.Stderr, "Couldn't handle a fatal error. Exiting...")
|
|
case <-panicHandlerDone:
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
|
|
// 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)
|
|
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)
|
|
f()
|
|
})
|
|
}
|
|
}
|