Eine Anwendung speichert eine Kundennachricht und veröffentlicht anschließend ein Ereignis für einen Worker. Wenn sie zwischen diesen Vorgängen abstürzt, ist die Nachricht zwar vorhanden, der Worker wird jedoch nie darüber informiert. Umgekehrt entsteht ein anderes Problem: Das Ereignis kann vorhanden sein, obwohl die Datenbankänderung noch nicht erfolgt ist.
Der Transaktions-Ausgang behebt diese Lücke beim doppelten Schreiben, indem er die geschäftliche Änderung und ein ausgehendes Ereignis in derselben Datenbanktransaktion speichert. Das ist eine wertvolle Garantie, sorgt jedoch nicht dafür, dass der gesamte Workflow genau einmal ausgeführt wird.
Formulieren Sie die erste Garantie präzise
Wird die Transaktion bestätigt, sind sowohl der Domänen-Eintrag als auch der Eintrag im Ausgangsordner vorhanden. Wird sie zurückgesetzt, sollte keiner von beiden vorhanden sein. Ein separater Relay liest den Ausgangsordner aus und veröffentlicht Ereignisse an den Broker.
In der AWS-Beschreibung des Musters werden diese Transaktionsgrenze und die Notwendigkeit, doppelte Nachrichten zu behandeln, erörtert. Ich halte es für sinnvoll, diese Garantien festzulegen, bevor man sich für eine Relay-Implementierung entscheidet.
Ein Outbox-Datensatz sollte über eine stabile Ereignis-ID, einen Mandantenkontext, einen Ereignistyp, eine Schemaversion sowie die von den Verbrauchern benötigte Domänenreferenz verfügen. Ob ein vollständiger Snapshot oder eine Referenz aufgenommen wird, hängt vom Zweck des Ereignisses und den Konsistenzanforderungen ab.
Das Relais verfügt weiterhin über ein Absturzfenster
Angenommen, das Relay veröffentlicht ein Ereignis erfolgreich und stürzt ab, bevor es die Zeile im Ausgangskorb als gesendet markiert hat. Beim nächsten Relay-Versuch kann es das Ereignis erneut veröffentlichen. Würde man es vor der Veröffentlichung als gesendet markieren, bestünde stattdessen die Gefahr, dass es verloren geht.
Ich gehe daher davon aus, dass der Verbraucher Duplikate erhalten kann. Bei mehreren Relay-Workern ist zudem eine Strategie zur Anspruchsabwicklung erforderlich, die unkontrollierte Konflikte verhindert und gleichzeitig eine Wiederherstellung ermöglicht, falls ein Worker ausfällt.
Der Veröffentlichungsstatus sollte Versuche, den nächsten möglichen Wiederholungszeitpunkt und den letzten aussagekräftigen Fehler enthalten. Ein ständig wachsender Ausgangsordner stellt einen Rückstand dar, der untersucht werden muss, und ist keine gesunde Warteschlange, nur weil die Datenbank Einfügungen akzeptiert.
Verbraucher an der Geschäftsgrenze idempotent machen
Für einen Verbraucher, dessen Wirkung sich auf lokale Datenbankoperationen beschränkt, kann ich die ID des verarbeiteten Ereignisses aufzeichnen und die Wirkung in einer Transaktion anwenden. Eine Eindeutigkeitsbeschränkung verhindert, dass zwei gleichzeitig ablaufende Lieferungen dieselbe Operation zweimal anwenden.
Externe Effekte sind schwieriger zu handhaben. Wenn der Verbraucher eine E-Mail versendet oder eine Zahlungsaktion auslöst, darf die Datenbanktransaktion den Remote-Dienst nicht einbeziehen. Für diesen Vorgang ist entweder ein Idempotenzschlüssel des Anbieters, ein dauerhafter Vorgangseintrag oder ein Abgleichpfad für ungewisse Ergebnisse erforderlich.
Die Einstellungen für die Broker-Übermittlung heben diese Anwendungsgrenze nicht auf. In einem JetStream-Consumer müssen das Bestätigungs- und das erneute Übermittlungsverhalten übereinstimmen, wenn die Anwendung die Aufgabe als sicher abgeschlossen betrachten kann. In der NATS-Consumer-Dokumentation können Sie diese Mechanismen für die bereitgestellte Konfiguration überprüfen.
Entscheiden Sie, welche Reihenfolge für die Domäne erforderlich ist
Eine globale Reihenfolge ist oft aufwendig und unnötig. Ein Gespräch benötigt möglicherweise eine eigene Abfolge, während nicht miteinander in Zusammenhang stehende Gespräche unabhängig voneinander ablaufen können. Ich ziehe es vor, diese Domänenanforderung auszudrücken, anstatt mich auf die zufällige Reihenfolge zu verlassen, in der die Worker ihre Aufgaben abschließen.
Verbraucher können eine aggregierte Version oder Sequenz verwenden, um Lücken und veraltete Ereignisse zu erkennen. Die Wiederherstellungsrichtlinie entscheidet dann, ob gewartet, der maßgebliche Zustand neu geladen oder eine Wiederholung angefordert werden soll.
Auch die Schema-Versionierung spielt eine Rolle. Eine Nachricht, die während einer Bereitstellung im Broker verblieben ist, könnte von älterem Code erzeugt worden sein. Konsumenten benötigen einen Kompatibilitätsplan für die Versionen, die noch ausgeliefert werden können.
Den gesamten Pfad bearbeiten
Ich überwache das Alter des ältesten noch nicht veröffentlichten Ereignisses, Veröffentlichungsfehler, Verzögerungen auf der Empfängerseite, wiederholte Zustellungen und das Volumen der „Dead-Letter“-Nachrichten. Diese Kennzahlen beschreiben verschiedene Fehlerquellen und sollten nicht zu einer einzigen Warteschlangenzahl zusammengefasst werden.
Meine Fehlertests stoppen das Relais nach der Veröffentlichung, stoppen den Konsumenten nach dessen Nebeneffekt und spielen ein aufgezeichnetes Ereignis erneut ab. Jeder Test prüft, ob sich das System wiederherstellen lässt, ohne dass der beabsichtigte Vorgang verloren geht oder dessen Wirkung sich vervielfacht.
Der Ausgangsordner gibt der Anwendung eine dauerhafte Zusage zur Veröffentlichung. Verbraucher und nachgelagerte Integrationen müssen diese Zusage jedoch noch nutzbar machen.
Aktualisiert am 25. September 2026.