fix: Crash-Robustheit + Performance in Backend und Frontend härten
Backend: recover() in allen langlebigen Goroutinen (neues internal/safego- Paket), MIME-Multipart-Tiefenlimit gegen Stack-Overflow, IMAP-Zeilenlängen- und FETCH-Result-Limits gegen OOM, MBOX-Buffer-Aliasing-Bug (Datenkorruption beim Import), ungeprüfte Type Assertions abgesichert, Data Race im API-Key-Rate-Limiter behoben, SMTP-Session-Panic führt jetzt zu 451-Retry statt Prozessabsturz. Performance: O(n²)-String-Concat in Mailparser und IMAP-Parser durch strings.Builder ersetzt. Frontend: Error Boundaries für Root und Mail-Detailansicht ergänzt (gab es vorher nicht), zahlreiche Guards gegen nil-Slices aus dem Backend-JSON die sonst .map()/.length-Crashes/White-Screens auslösten, defekte JSON-Antworten in api/core.ts abgefangen, zwei React-Key-Bugs bei löschbaren Listen korrigiert. Verifiziert auf 192.168.1.132: Build und Tests der geänderten Pakete fehlerfrei, keine Regressionen gegenüber vorbestehendem Stand. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019j28kGcaJAhBnrYX34hGdt
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
0fa4fad49d
commit
798cb2817c
@@ -0,0 +1,32 @@
|
||||
// Package safego starts background goroutines that cannot take the process
|
||||
// down. A panic inside a detached goroutine is fatal for the whole binary in
|
||||
// Go — there is no per-goroutine boundary like net/http provides for request
|
||||
// handlers. Every "fire and forget" goroutine in archivmail (mail sending,
|
||||
// importer runs, boot-resume jobs) therefore goes through Go/Run.
|
||||
package safego
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
// Run executes fn synchronously and recovers from a panic, logging it with the
|
||||
// given name. It returns true when fn completed without panicking.
|
||||
func Run(logger *slog.Logger, name string, fn func()) (ok bool) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ok = false
|
||||
if logger != nil {
|
||||
logger.Error("recovered from panic in background task",
|
||||
"task", name, "panic", fmt.Sprintf("%v", r))
|
||||
}
|
||||
}
|
||||
}()
|
||||
fn()
|
||||
return true
|
||||
}
|
||||
|
||||
// Go runs fn in a new goroutine, recovering and logging any panic.
|
||||
func Go(logger *slog.Logger, name string, fn func()) {
|
||||
go Run(logger, name, fn) //nolint:errcheck // result is irrelevant for detached tasks
|
||||
}
|
||||
Reference in New Issue
Block a user