mirror of
https://github.com/laoxong/nofx.git
synced 2026-06-04 09:58:22 +08:00
3ca95b294d
* feat: integrate NOFXi agent into dev * Enhance NOFXi agent workflow and diagnostics
60 lines
1.6 KiB
Go
60 lines
1.6 KiB
Go
// Package safe provides panic-recovery wrappers for goroutines.
|
|
// A panic in any bare goroutine tears down the entire process.
|
|
// Use safe.Go instead of `go func()` in long-running or critical paths.
|
|
package safe
|
|
|
|
import (
|
|
"fmt"
|
|
"nofx/logger"
|
|
"runtime/debug"
|
|
)
|
|
|
|
// Go launches fn in a new goroutine with automatic panic recovery.
|
|
// If fn panics, the panic is logged (with stack trace) but the process
|
|
// continues running. An optional onPanic callback receives the recovered value.
|
|
func Go(fn func(), onPanic ...func(recovered interface{})) {
|
|
go func() {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
stack := string(debug.Stack())
|
|
logger.Errorf("🔥 goroutine panic recovered: %v\n%s", r, stack)
|
|
|
|
for _, cb := range onPanic {
|
|
func() {
|
|
defer func() {
|
|
if r2 := recover(); r2 != nil {
|
|
logger.Errorf("🔥 onPanic callback itself panicked: %v", r2)
|
|
}
|
|
}()
|
|
cb(r)
|
|
}()
|
|
}
|
|
}
|
|
}()
|
|
fn()
|
|
}()
|
|
}
|
|
|
|
// GoNamed is like Go but tags the log line with a human-readable name.
|
|
func GoNamed(name string, fn func(), onPanic ...func(recovered interface{})) {
|
|
Go(func() {
|
|
fn()
|
|
}, append([]func(interface{}){
|
|
func(r interface{}) {
|
|
logger.Errorf("🔥 [%s] goroutine panicked: %v", name, r)
|
|
},
|
|
}, onPanic...)...)
|
|
}
|
|
|
|
// Must converts a panic into an error. Useful inside goroutines where you
|
|
// want to handle panics as errors in the caller's recovery flow.
|
|
func Must(fn func()) (err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
err = fmt.Errorf("panic: %v\n%s", r, debug.Stack())
|
|
}
|
|
}()
|
|
fn()
|
|
return nil
|
|
}
|