Zuverlässigkeit und Beständigkeit von Workflows
Auf dieser Seite
Warum Beständigkeit alles verändert
Stellen Sie sich eine Pipeline mit zehn Schritten zur Verarbeitung einer Batch von Rechnungen vor: Extraktion, Validierung, Modellaufruf, Datenbank-Schreibvorgang, Benachrichtigung. In einem herkömmlichen Python-Skript führt ein Absturz am Schritt 7 dazu, dass Sie bei Schritt 1 beginnen müssen. Die ersten sechs Schritte werden erneut ausgeführt, was zu erheblichen Problemen führt, falls einer dieser Schritte Daten in eine Datenbank geschrieben oder eine Nachricht gesendet hat. Mit einem beständigen Workflow (durable workflow) setzt das System exakt bei Schritt 7 fort. Es überspringt die ersten sechs Schritte, vermeidet die Duplizierung von Aktionen und verliert keine Daten.
Diese Fähigkeit beruht auf einem spezifischen Mechanismus namens Event Sourcing. Das Verständnis dieses Konzepts ist essenziell, da es die Einschränkungen erklärt, die Sie später antreffen werden.
Event Sourcing: Das Kernprinzip
Event Sourcing protokolliert jede Workflow-Aktion als unveränderliches Ereignis in einem Log. Der Unterschied zu einem traditionellen Ansatz lässt sich in einem Satz zusammenfassen: Anstatt nur den aktuellen Zustand zu speichern (z. B. „im Gange, Schritt 7”), behält die Plattform eine vollständige Historie der Operationen und ihrer Ergebnisse. Eine Workflow-Ausführung mit zwei Aktivitäten hinterlässt folgenden Verlauf:
- Der Workflow startet und erhält Eingabeparameter → Ereignis protokolliert
- Der Workflow ruft Aktivität A auf → Ereignis protokolliert
- Aktivität A schließt mit einem Ergebnis ab → Ereignis protokolliert
- Der Workflow ruft Aktivität B auf → Ereignis protokolliert
- Aktivität B schließt ab → Ereignis protokolliert
- Der Workflow gibt sein finales Ergebnis zurück → Ereignis protokolliert
Das System persistiert jeden Schritt vor dem Übergang zum nächsten. Es gibt keinen Zeitraum, in dem eine Aktion stattfindet, ohne dass das Log davon Kenntnis hat. Dieses Log wird zur einzigen Wahrheit (single source of truth); der Workflow-Zustand existiert an keiner anderen Stelle.
Automatisches Wiederspielen: Wiederherstellung nach einem Fehler
Wenn ein Worker abstürzt, übernimmt ein neuer Worker das Workflow-Protokoll und spielt den Workflow-Code von vorne ab. Der Begriff „Wiederspielen” (replay) überrascht viele: Der Code startet zwar erneut bei Zeile eins, aber für jede Aktivität, die bereits abgeschlossen wurde, ruft der Engine Ihre Funktion nicht erneut auf. Stattdessen ersetzt er das protokollierte Ergebnis aus dem Log. Der Workflow schreitet mit Lesegeschwindigkeit voran, bis er auf die erste unvollendete Aktivität trifft. Erst dann setzt die eigentliche Arbeit fort.
Aktivitäten, die bereits erfolgreich waren, werden während eines Wiederspiels niemals erneut ausgeführt. Das folgende Beispiel macht diese Garantie für den sensibelsten Fall greifbar: das Senden einer E-Mail.
import mistralai.workflows as workflows
@workflows.activity()
async def send_email(recipient: str, content: str) -> dict:
"""Diese Aktivität wird nur einmal ausgeführt,
auch wenn der Workflow mehrere Male wiederspielt."""
response = await email_service.send(recipient, content)
return {"status": "sent", "id": response.id}
@workflows.workflow.define(name="notification_workflow")
class NotificationWorkflow:
@workflows.workflow.entrypoint
async def run(self, recipient: str) -> dict:
# Wenn der Workflow nach dem Senden der E-Mail abstürzt,
# wird die E-Mail während des Wiederspiels NICHT erneut gesendet.
email_result = await send_email(recipient, "Ihr Bericht ist bereit")
# Der Workflow setzt hier fort
log_result = await log_notification(recipient, email_result)
return log_result
Fehlertoleranz: Abgedeckte Szenarien
Die Plattform behandelt vier Arten von Vorfällen, ohne dass Sie eine einzige Zeile Code schreiben müssen. Erstens, ein Worker-Absturz: Der Python-Prozess stoppt abrupt aufgrund eines Speicherfehlers, eines kill-Signals oder eines Server-Neustarts. Ein anderer Worker übernimmt den Workflow exakt dort, wo er stehen geblieben ist. Zweitens, ein vorübergehender Netzwerkfehler: Ein API-Aufruf schlägt fehl aufgrund eines Timeouts. Die Retry-Richtlinie startet die Aktivität automatisch neu mit exponentiellem Backoff, wobei die Verzögerungen zunehmen, um eine überlastete Dienstleistung nicht zu überlasten.
Drittens, Fehler in Ihrem eigenen Code: Eine in einer Aktivität ausgelöste Ausnahme wird eine definierte Anzahl von Malen basierend auf der konfigurierten Richtlinie neu versucht, bevor sie endgültig fehlschlägt. Viertens, vorübergehende Unverfügbarkeit eines Drittanbieterdienstes. Die Wirkung ist hier dramatisch: Wenn eine Partner-API für zehn Minuten ausfällt, schlägt Ihre nächtliche Pipeline nicht mehr fehl. Ausstehende Aktivitäten starten neu, sobald der Dienst verfügbar ist, und die Verarbeitung endet lediglich zehn Minuten später.
Die Determinismus-Einschränkung
Wiederspielen hat einen Preis. Damit das Log-Wiederspiel die ursprüngliche Ausführung treu reproduziert, muss der Workflow-Code (nicht die Aktivitäten) deterministisch sein. Bei gleichen Eingaben muss er die gleiche Sequenz von Operationen erzeugen. Wenn Ihr Workflow basierend auf if datetime.now().hour < 12 verzweigt, könnte ein Wiederspiel heute Abend den anderen Zweig nehmen und das Log vollständig desynchronisieren.
Deshalb dürfen Sie in Workflow-Code niemals Folgendes tun:
datetime.now()verwenden → verwenden Sieworkflow.now()uuid.uuid4()verwenden → verwenden Sieworkflow.uuid4()random.random()verwenden → verwenden Sieworkflow.random()- Netzwerk- oder I/O-Aufrufe direkt durchführen → verschieben Sie sie in eine Aktivität
Diese drei Substitutionen geben Werte zurück, die während des ersten Durchlaufs protokolliert und danach identisch wiederspielen werden. Wir werden diese Einschränkung in Lektion 8, die sich auf Determinismus konzentriert, detailliert erläutern.
Vergleich mit traditionellen Ansätzen
| Ansatz | Wiederherstellung nach Fehler | Ausführungsgarantie | Komplexität |
|---|---|---|---|
| Einfaches Python-Skript | Nein | Keine | Niedrig |
| Nachrichtenwarteschlange (Celery, RQ) | Teilweise | Mindestens einmal | Mittel |
| Cron + Datenbank | Manuell | Abhängig von der Implementierung | Hoch |
| Mistral Workflows (Temporal) | Automatisch | Genau einmal (logisch) | Niedrig (SDK) |
Achten Sie besonders auf die Spalte Komplexität. Eine Nachrichtenwarteschlange scheint am Anfang einfach, aber ihre teilweise Wiederherstellung zwingt Sie dazu, Zustandsmanagement-Logik zu schreiben, die das SDK von Haus aus bereitstellt.
Genau einmal: Eine logische Garantie
Die Plattform garantiert, dass Ihre Workflow-Logik genau einmal ausgeführt wird. Wenn eine Aktivität erfolgreich ist, protokolliert das System das Ergebnis und führt sie nie erneut aus. Wenn sie fehlschlägt, versucht das System sie gemäß der konfigurierten Richtlinie erneut.
Das Wort „logisch” ist keine Dekoration. Auf Netzwerkebene könnte ein Aufruf tatsächlich zweimal gesendet werden: Ihre Anfrage zur Erstellung eines Kunden erreicht das CRM, aber die Bestätigung geht im Transit verloren. Aus Ihrer Perspektive ist die Aktivität fehlgeschlagen und wird erneut versucht, obwohl der Kunde bereits existiert. Dies erzeugt die Notwendigkeit für idempotente Aktivitäten, die auch bei mehrmaligem Aufruf mit denselben Parametern das gleiche Ergebnis erzeugen. In der Praxis bedeutet dies, dass Sie einen PUT auf einer stabilen ID bevorzugen sollten, anstatt einen POST, der bei jedem Aufruf eine neue Zeile erstellt.
Kernaussagen
- Event Sourcing protokolliert jeden Schritt als unveränderliches Ereignis in einem Log
- Automatisches Wiederspielen ermöglicht es Ihnen, einen unterbrochenen Workflow fortzusetzen, ohne ausgeführte Aktivitäten erneut auszuführen
- Die Plattform behandelt Abstürze, Netzwerkfehler und Dienstausfälle automatisch
- Workflow-Code muss deterministisch sein, damit Wiederspielen funktioniert
- Aktivitäten müssen idempotent sein, um Konsistenz während von Retries zu gewährleisten
- Die Ausführungsgarantie ist logisch genau einmal