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
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"aether/internal/storage"
|
||||
"aether/pkg/bg"
|
||||
)
|
||||
|
||||
// idleInterval ist die Pause, wenn nichts zu tun ist.
|
||||
@@ -67,7 +68,13 @@ func (w *Worker) Run(ctx context.Context) {
|
||||
|
||||
for {
|
||||
wait := idleInterval
|
||||
if w.step(ctx) {
|
||||
// **Je Auftrag abgesichert, nicht je Arbeiter.** Fängt man eine Panik
|
||||
// um die ganze Schleife ab, überlebt zwar der Prozess – aber der
|
||||
// Arbeiter ist tot, und von da an wird still keine Datei mehr erkannt.
|
||||
// So kostet ein unverdauliches Dokument genau sich selbst.
|
||||
var etwasGetan bool
|
||||
bg.Run("Texterkennung", func() { etwasGetan = w.step(ctx) })
|
||||
if etwasGetan {
|
||||
wait = busyInterval
|
||||
}
|
||||
select {
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"aether/internal/storage"
|
||||
"aether/pkg/bg"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -254,7 +255,9 @@ func (c *Collector) referencedKeys(ctx context.Context) (map[string]bool, error)
|
||||
// im Intervall. Der erste Durchlauf ist verzögert, damit er nicht mit dem
|
||||
// Hochfahren konkurriert.
|
||||
func (c *Collector) Start(ctx context.Context, onDone func(Result)) {
|
||||
go func() {
|
||||
// Über bg.Go: Der GC liest Verzeichnisse und Datenbankzeilen, und ein
|
||||
// Absturz darin darf nicht den Dienst mitnehmen, den er aufräumen soll.
|
||||
bg.Go("Speicherbereinigung", func() {
|
||||
timer := time.NewTimer(5 * time.Minute)
|
||||
defer timer.Stop()
|
||||
|
||||
@@ -282,7 +285,7 @@ func (c *Collector) Start(ctx context.Context, onDone func(Result)) {
|
||||
}
|
||||
timer.Reset(Interval)
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
|
||||
// DerivedUsage: Wie viel Platz die **abgeleiteten** Daten belegen.
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"aether/internal/auth"
|
||||
"aether/internal/files"
|
||||
"aether/internal/storage"
|
||||
"aether/pkg/bg"
|
||||
"aether/pkg/middleware"
|
||||
"aether/pkg/response"
|
||||
)
|
||||
@@ -229,10 +230,10 @@ func (h *Handler) Download(w http.ResponseWriter, r *http.Request) {
|
||||
// abgebrochen, sobald die Antwort draußen ist – die Zählung verlor das
|
||||
// Rennen fast immer und der Zähler blieb auf 0 stehen.
|
||||
zaehlCtx, abbrechen := context.WithTimeout(context.WithoutCancel(r.Context()), 5*time.Second)
|
||||
go func() {
|
||||
bg.Go("Freigabe-Zaehler", func() {
|
||||
defer abbrechen()
|
||||
h.store.IncrementDownloads(zaehlCtx, token)
|
||||
}()
|
||||
})
|
||||
|
||||
w.Header().Set("Content-Type", f.MimeType)
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename=%q`, f.Name))
|
||||
|
||||
Reference in new issue
Block a user