Zum Inhalt springen

Fehler und Resilienz

Wenn etwas schiefgeht: Fehlerresilienz

Die vorherigen Kapitel haben den Idealfall beschrieben: jeder Dienst ist erreichbar, jede Antwort kommt rechtzeitig. In der Praxis geht regelmäßig etwas schief. Ein Sprachmodell antwortet nicht, eine Datenbank ist kurzzeitig unerreichbar, ein Worker-Prozess stürzt ab. Die Frage ist, wie das System damit umgeht.

Begriffe zuerst: In diesem Kapitel bedeutet failed den finalen fachlichen Endstatus einer Email. Die Verarbeitung ist abgebrochen und ein Mensch muss eingreifen. Nicht zu verwechseln mit dead auf Queue-Ebene (siehe email-rag-ki-worker-und-queues): Ein dead Queue-Eintrag bedeutet nur, dass für diesen konkreten Job-Retry keine automatische Wiederholung mehr erfolgt. Beide Ebenen werden in diesem Kapitel gemeinsam beleuchtet.

Strategien für Fehler

Das System kennt mehrere grundlegende Strategien, die je nach Fehlertyp kombiniert werden:

Wiederholung mit Wartezeit (Retry mit Backoff): Der fehlgeschlagene Schritt wird erneut versucht, mit steigenden Wartezeiten zwischen den Versuchen. Die Standard-Wartezeiten sind 30, 120 und 600 Sekunden. Nach drei Versuchen wird die Email als fehlgeschlagen markiert. Für den Versand selbst gilt zusätzliche Idempotenz-Garantie: der Send-Attempt wird pro Draft genau einmal erzeugt und bei Retries fortgeschrieben (Details in email-rag-ki-versand-feedback).

Fallback auf reduzierten Betrieb: Wenn ein optionaler Dienst ausfällt (Qdrant für die Vektorsuche, ArangoDB für den Graphen), arbeitet das System mit reduziertem Kontext weiter. Die Email wird als partially_indexed markiert und später nachindexiert.

Dead Letter und manuelle Prüfung: Emails, die nach allen Versuchen nicht verarbeitet werden konnten, landen im Dead-Letter-Status. Sie werden nicht gelöscht, sondern bleiben zur manuellen Prüfung im System.

Fehler schlägt durchLLM, DB, IMAP, Qdrant, ...
Retry mit Backoff30s, 120s, 600s
FallbackReduzierter Betrieb
Dead LetterManuelle Prüfung
ErfolgWeiter in der Pipeline
partially_indexedSpäter nachindexiert
Audit-LogLückenlos protokolliert

Fehlerbehandlung nach Dienst

Jeder Dienst hat eine eigene Fehlerstrategie:

  • IMAP-Fehler: Unbegrenzte Wiederholung mit exponentiellem Backoff. Der Poller versucht es beim nächsten Cron-Lauf erneut.
  • MariaDB-Fehler: Sofortiger Reconnect. Alle Service-Caches werden geleert, der Worker erstellt seine Dienste neu. Bei anhaltendem Ausfall wartet der Worker.
  • LLM-Timeout: Ein Wiederholungsversuch. Schlägt auch der fehl, wird die Email in die manuelle Queue gestellt.
  • LLM-JSON-Fehler: Das Modell liefert ungültiges JSON. Ein Retry mit angepasstem Prompt. Danach Standardwerte.
  • Qdrant/ArangoDB: Drei Versuche mit Backoff. Bei anhaltendem Ausfall: partially_indexed. Der periodische Cron-Sync füllt die fehlenden Daten nach.
  • SMTP-Fehler: Drei Versuche. Der freigegebene Entwurf bleibt als approved stehen und wird beim nächsten Versuch erneut gesendet.

Stuck Processing: die Sicherheitsleine

Ein besonderer Fall: was passiert, wenn ein Worker-Prozess abstürzt, während er eine Email verarbeitet? Der Queue-Eintrag bleibt im Status processing hängen, niemand holt ihn ab.

Dafür gibt es den Stuck-Processing-Reset: der CleanupService prüft stündlich, ob Queue-Einträge länger als 600 Sekunden im Status processing stehen. Falls ja, werden sie auf failed zurückgesetzt und landen im normalen Retry-Kreislauf.

Jeder Fehler, jeder Retry und jedes Fallback wird im Audit-Log protokolliert. So lässt sich nachvollziehen, warum eine Email auf einem bestimmten Weg durch das System gelaufen ist.