fix(bg): Hintergrundarbeit reisst den Prozess nicht mehr mit
Das Vorschaubild entstand in einer nackten Goroutine. Chis Recoverer haengt
am Anfragebehandler und sieht davon nichts -- eine Panik im Bilddekodierer
nahm den ganzen Go-Prozess mit, ausgeloest durch einen gewoehnlichen
Upload. Die Bibliothek ist seit ef60497 aktuell; das schloss **diese**
Luecke. Dies hier schliesst die **Gattung**.
pkg/bg mit zwei Funktionen, und der Unterschied ist keine Feinheit:
* bg.Go(name, fn) -- Goroutine, die eine Panik ueberlebt
* bg.Run(name, fn) -- dasselbe ohne eigene Goroutine, fuer Schleifen
Faengt man eine Panik um den **ganzen** Arbeiter ab, ueberlebt der Prozess
-- aber der Arbeiter ist tot, und von da an wird still keine Datei mehr
erkannt. Der OCR-Arbeiter sichert deshalb jeden **Auftrag** einzeln ab.
Umgestellt: Vorschaubild, Bestand nachtragen, Freigabe-Zaehler,
Speicherbereinigung, OCR-Arbeiter. Eine nackte Goroutine bleibt mit
Begruendung im Code -- die Signalbehandlung; ein recover braechte dort
nichts, weil main ohnehin wartete.
Aufgefangene Paniken werden mit Stapel und Herkunft protokolliert. Vier
Tests, darunter der wichtige: Eine Schleife laeuft nach einer Panik im
dritten Durchgang weiter.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
89f0817dcb
commit
c26bcba012
7 files changed
+156
-17
No files matched your search
@@ -0,0 +1,53 @@
|
||||
// Package bg startet Hintergrundarbeit, die den Prozess nicht mitreißen kann.
|
||||
//
|
||||
// **Der Anlass ist gemessen, nicht theoretisch.** Aether erzeugt das
|
||||
// Vorschaubild einer hochgeladenen Datei in einer eigenen Goroutine. Chis
|
||||
// `Recoverer` hängt am Anfragebehandler und sieht davon nichts – eine Panik
|
||||
// dort nimmt den **ganzen Go-Prozess** mit. Am 12.09.2026 stand dafür sogar
|
||||
// eine passende Lücke offen (GO-2026-5061, Panik im WebP-Dekodierer): Ein
|
||||
// gewöhnlicher Bild-Upload hätte den Server umgelegt.
|
||||
//
|
||||
// Die Bibliothek zu aktualisieren schließt **diese** Lücke. Diese Datei
|
||||
// schließt die **Gattung**: Bilddekodierer, Fremdformate und externe Programme
|
||||
// sind Felder, in denen regelmäßig etwas gefunden wird, und keines davon darf
|
||||
// über einen Weg erreichbar sein, an dessen Ende der Prozess stirbt.
|
||||
//
|
||||
// Was hier *nicht* passiert: Fehler verschlucken. Eine aufgefangene Panik wird
|
||||
// mit Stapel protokolliert. Sie ist ein Fehler und bleibt einer – sie reißt
|
||||
// nur nichts mehr mit.
|
||||
package bg
|
||||
|
||||
import (
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Go startet fn in einer Goroutine, die eine Panik überlebt.
|
||||
//
|
||||
// name steht im Logeintrag und sollte sagen, *was* da lief ("Vorschaubild",
|
||||
// "Texterkennung") – eine Zeile „panic recovered" ohne Herkunft hilft um drei
|
||||
// Uhr nachts niemandem.
|
||||
func Go(name string, fn func()) {
|
||||
go Run(name, fn)
|
||||
}
|
||||
|
||||
// Run ist dasselbe ohne eigene Goroutine: für Schleifen, in denen **ein**
|
||||
// Durchgang scheitern darf, ohne dass die Schleife endet.
|
||||
//
|
||||
// Der Unterschied ist keine Feinheit. Fängt man eine Panik um den ganzen
|
||||
// Arbeiter herum ab, überlebt der Prozess – aber der Arbeiter ist tot, und
|
||||
// von da an wird still keine Datei mehr erkannt. Fängt man sie um den
|
||||
// einzelnen Auftrag ab, verliert man den einen Auftrag und macht weiter.
|
||||
func Run(name string, fn func()) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Error().
|
||||
Str("wo", name).
|
||||
Interface("panik", r).
|
||||
Str("stapel", string(debug.Stack())).
|
||||
Msg("Hintergrundarbeit abgestürzt – aufgefangen")
|
||||
}
|
||||
}()
|
||||
fn()
|
||||
}
|
||||
Reference in new issue
Block a user