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
33 lines
1.1 KiB
Go
33 lines
1.1 KiB
Go
// 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
|
|
}
|