mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-12 07:16:56 +08:00
security+reliability: remove public decrypt endpoint, add panic recovery for goroutines
Security: - Remove /api/crypto/decrypt from public routes. The endpoint allowed anyone to decrypt ciphertext without authentication. Internal callers (exchange/model handlers) use the service directly and are behind auth. Reliability: - Add safe.Go / safe.GoNamed panic recovery wrapper (safe/go.go). Previously 31 goroutines had zero recover() calls — a single panic in any trader goroutine would crash the entire process. - Apply safe.GoNamed to all trader launch paths: - StartAll, RestoreRunning, LoadSingleTrader auto-start - API handler start/restart endpoints - Panics are now logged with full stack traces instead of crashing.
This commit is contained in:
59
safe/go.go
Normal file
59
safe/go.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// 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
|
||||
}
|
||||
Reference in New Issue
Block a user