Der Wert von Durable Task liegt nicht darin, jeden Hintergrunddienst, jede Nachrichtenwarteschlange oder jede Datenbank zu ersetzen, sondern darin, Prozesse zu organisieren, die lange dauern, auf ein externes Ereignis warten oder nach der Ausführung eines Teils ihrer Schritte unterbrochen werden können. Ein .NET-Blog stellt fünf praktische Beispiele mit dem Durable Task .NET SDK in Version 1.26.0 zusammen mit Durable Task Scheduler vor und betont, dass das Tool den Verlauf der Orchestrierung speichert, nicht jedoch einen angehaltenen CLR-Ausführungsstapel wiederherstellt.
Der zentrale Gedanke ist die Trennung zwischen dem, was die Workflow-Engine koordiniert, und dem, wofür die Anwendung verantwortlich bleibt. Durable Task kann Fortschrittspunkte speichern, warten, ohne einen belegten Ausführungsthread aufrechtzuerhalten, und den Orchestrierungscode anhand der aufgezeichneten Ergebnisse erneut ausführen. Es entscheidet jedoch nicht über Benutzerberechtigungen, garantiert keine genau-einmalige Ausführung externer Seiteneffekte und bestimmt weder allein, welche Ressourcen sicher gelöscht werden können, noch ob eine Zahlung tatsächlich eingegangen ist.
Eine menschliche Genehmigung bedeutet nicht, den Worker anzuhalten
Bei der Rechnungsverarbeitung kann jede Rechnung in einer eigenen untergeordneten Orchestrierung ausgeführt werden. Rechnungen, die keine Prüfung benötigen, setzen ihren Weg fort, während eine Rechnung, die eine menschliche Genehmigung erfordert, auf ein externes Ereignis und eine belastbare Zeitüberschreitung wartet. Wenn der Worker ausfällt, kann ein anderer Worker die Orchestrierung erneut ausführen und zum Wartepunkt zurückkehren, statt den Zustand manuell wiederaufbauen zu müssen.
Dennoch ist das Genehmigungsereignis lediglich ein Signal. Ein dokumentierter Endpunkt muss die endgültige Entscheidung atomar im Anwendungsspeicher festhalten, bevor er das Signal sendet, und der Buchhaltungsschritt muss eine stabile Bereitstellungsidentität sowie einen unveränderlichen Anforderungs-Fingerabdruck prüfen. Wird der Buchungssatz akzeptiert, aber die Bestätigung der Aktivität geht verloren, reicht der Durable-Task-Verlauf nicht aus, um eine Wiederholung zu verhindern; erforderlich ist vielmehr ein Abstimmungsprotokoll mit dem Buchhaltungssystem.
Bereitstellung einer Azure-Umgebung: Wo endet die Rolle von ARM?
Der Beitrag erläutert, dass ARM und Bicep für die Bereitstellung bestimmter Ressourcen ausreichen können, da sie Abhängigkeiten ordnen, parallele Ausführung ermöglichen und den gewünschten Zustand mit stabilen Identitäten erneut anwenden. Daher lohnt es sich nicht, mit Durable Task ein Bereitstellungsschema neu aufzubauen, das ARM bereits bereitstellt.
Der Nutzen zeigt sich, wenn der Ablauf über die Ressourcenbereitstellung hinausgeht und die Annahme einer Mandantenanforderung, die Fortschrittsmeldung an den Mandanten, das Warten auf die Bereitschaft und anschließend die Aktivierung des Mandanten umfasst. Das Beispiel schlägt vor, die Initialisierungsanforderung und ihre IDs zusammen mit einer Outbox in der Anwendungsdatenbank zu speichern und anschließend eine Orchestrierung zu verwenden, die die Phasen für Netzwerk, Datenbank, Speicher, Anwendung und DNS sowie die Bereitschaftsprüfung verbindet. Die Azure-Vorgänge selbst benötigen weiterhin Betriebsprotokolle, stabile Identitäten und eine Abstimmung, wenn Antworten verloren gehen.
Der Beitrag warnt außerdem davor, Kompensation als Rückgängig-Schaltfläche zu betrachten. Azure kann nach einem Speicherfehler weiterhin eine Datenbank erstellen. Daher muss verhindert werden, dass ein alter Versuch neue Vorgänge startet; zuvor gesendete Vorgänge müssen geprüft werden, und es dürfen nur Ressourcen gelöscht werden, die ausschließlich dem Versuch gehören, nachdem sichergestellt wurde, dass keine verspäteten Vorgänge sie erneut erstellen können. Wenn sich Zustand oder Besitz nicht nachweisen lassen, lautet das sichere Ergebnis NeedsIntervention und nicht ein spekulatives Löschen.
Das Ablaufen einer Zahlungsfrist ist keine Ablehnung
In einem Abonnementzyklus kann die Antwort des Zahlungsanbieters verschwinden, nachdem der Vorgang akzeptiert wurde. Eine sofortige Wiederholung kann eine doppelte Belastung auslösen, während die Einstufung als abgelehnt eine irreführende Benachrichtigung versenden kann. Das Beispiel schlägt vor, jeden Zahlungszyklus mit einer Zyklus-ID und einem stabilen Zahlungsschlüssel zu verknüpfen und anschließend Durable-Timer, Rückrufe, regelmäßige Prüfungen und eine festgelegte Kulanzfrist zu verwenden.
Das Zahlungsbuch bleibt die maßgebliche Quelle für die Zustände Unknown, Pending, Declined, Paid und NotCharged. Der Zyklus wechselt erst zum nächsten, wenn der Beleg bestätigt und der aktuelle Zyklus geschlossen wurde. Läuft die Frist ab, während der Zustand weiterhin ungeklärt ist, lautet das Ergebnis NeedsReconciliation, statt den Erfolg oder Misserfolg der Zahlung anzunehmen.
Verspätete Ereignisse benötigen Schutz am Ziel
Bei der Aktualisierung eines Suchindex für Nachrichtenartikel kann Version 12 nach Version 13 eintreffen oder die Indizierungsvorgänge in umgekehrter Reihenfolge abgeschlossen werden. Eine Durable Entity kann die höchste bereits gesehene Version speichern und die Aktualisierungssequenz ihrer Zähler verfolgen, sperrt jedoch den externen Index nicht und verhindert nicht, dass zwei Anforderungen parallel schreiben.
Daher muss das Ziel selbst eine atomare Versionssperre durchsetzen, die das Schreiben einer älteren Version ablehnt, nachdem eine neuere Version festgeschrieben wurde. Außerdem benötigt das System eine zuverlässige Inbox, einen Dispatcher zur Nachverfolgung und eine regelmäßige Abstimmung mit der Quelle. Selbst das Muster einer Orchestrierung mit einer einzigen ID bietet keine Garantie für eine genau-einmalige Ausführung externer Seiteneffekte.
Was bedeutet das für KI-Agenten?
In einem Workflow für einen Incident-Assistenten muss der konkrete Modellvorschlag gespeichert, die Genehmigung durch den Ingenieur abgewartet und anschließend das genehmigte Tool nach einem möglichen Ausfall ausgeführt werden. Der Wert liegt hier in der Wiederherstellung desselben Genehmigungs- und Entscheidungswegs, nicht in der erneuten Generierung eines neuen Vorschlags nach jeder Wiederholung. Für die Identität des Vorschlags, die Berechtigung des Tools und die Verhinderung der Ausführung einer alten oder doppelten Anforderung bleibt jedoch die Anwendung verantwortlich.
Die praktische Schlussfolgerung aus den fünf Beispielen lautet, dass Durable Task geeignet ist, wenn das Speichern dessen, „was als Nächstes geschehen soll“, selbst zu einem System wird. Wenn die Anwendung bereits über Warteschlangen, Timer und klare Abstimmungsprotokolle verfügt oder das externe System eine zuverlässige Orchestrierung wie ARM bereitstellt, kann das Framework jedoch mehr Komplexität als Nutzen hinzufügen. Außerdem beruhen alle Beispiele auf expliziten externen Grenzen: einem maßgeblichen Protokoll, einem Idempotenzschlüssel, einer Versionssperre, einer Outbox oder einem Abstimmungsprotokoll.