From d648614611b6a93f8648af1506051387cec628e2 Mon Sep 17 00:00:00 2001 From: Hein Date: Tue, 30 Jun 2026 13:49:51 +0200 Subject: [PATCH] feat(config): add PanicHandler to Config for custom recovery --- pkg/server/interfaces.go | 4 ++++ pkg/server/manager.go | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/pkg/server/interfaces.go b/pkg/server/interfaces.go index 6aeba53..a6fb1c4 100644 --- a/pkg/server/interfaces.go +++ b/pkg/server/interfaces.go @@ -42,6 +42,10 @@ type Config struct { // AutoTLSEmail is the email for Let's Encrypt registration (optional but recommended) AutoTLSEmail string + // PanicHandler is called when a request handler panics. + // If nil, the default middleware.PanicRecovery is used (logs, records metric, returns 500). + PanicHandler func(w http.ResponseWriter, r *http.Request, rcv any) + // Graceful shutdown configuration // ShutdownTimeout is the maximum time to wait for graceful shutdown // Default: 30 seconds diff --git a/pkg/server/manager.go b/pkg/server/manager.go index 2e2c85f..619e1b1 100644 --- a/pkg/server/manager.go +++ b/pkg/server/manager.go @@ -452,8 +452,19 @@ func newInstance(cfg Config) (*serverInstance, error) { handler = gz(handler) } - // Wrap with the panic recovery middleware - handler = middleware.PanicRecovery(handler) + // Wrap with panic recovery — use caller-supplied handler if provided + if cfg.PanicHandler != nil { + handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer func() { + if rcv := recover(); rcv != nil { + cfg.PanicHandler(w, r, rcv) + } + }() + handler.ServeHTTP(w, r) + }) + } else { + handler = middleware.PanicRecovery(handler) + } // Configure TLS if any TLS option is enabled tlsConfig, certFile, keyFile, err := configureTLS(cfg) @@ -475,6 +486,9 @@ func newInstance(cfg Config) (*serverInstance, error) { // The GODEBUG=http2xconnect=1 flag is read by net/http's init(); setting it here // ensures it propagates to subprocesses and any future process restarts. // For the current process, set GODEBUG=http2xconnect=1 in the environment before launch. + if httpServer.Protocols == nil { + httpServer.Protocols = &http.Protocols{} + } if cfg.HTTP2 { if existing := os.Getenv("GODEBUG"); !strings.Contains(existing, "http2xconnect=1") { if existing == "" {