Jeder will Echtzeit-Updates, bis er merkt, dass „schnell“ und „korrekt“ nicht dasselbe sind. In einem verteilten System können Ereignisse sich mit Lichtgeschwindigkeit bewegen und trotzdem in der falschen Reihenfolge ankommen. WebSockets brechen ab und verbinden sich neu. Message Broker liefern Pakete erneut aus. Background-Worker kämpfen gegen Timeout-Abbrüche an. Das Ergebnis? Ein Client sieht Ereignis 42, dann Ereignis 40 und dann einen Snapshot, der behauptet, das System sei bereits bei Ereignis 45. Wenn Sie langlaufende Agenten-Workflows entwickeln, ist dieses Chaos kein Sonderfall. Es ist der Normalzustand. Korrigieren Sie die Reihenfolge Ihrer Ereignisse, bevor Sie sich darum kümmern, Millisekunden bei der Zustellung einzusparen.

Die chaotische Realität von „Echtzeit“

Echtzeit ist eine Transporteigenschaft. Sie beschreibt, wie schnell ein Paket über eine Leitung wandert, nicht ob die Geschichte, die es erzählt, Sinn ergibt. Langlaufende Aufgaben verstärken jede Inkonsistenz, da sie sich über die Zeit erstrecken. Ein Modelltraining-Job, ein mehrstufiger Genehmigungsprozess oder eine Video-Rendering-Pipeline können über Minuten oder Stunden hinweg Dutzende von Ereignissen aussenden. In diesem Zeitfenster kann alles schiefgehen.

Ein Broker könnte eine Nachricht erneut versuchen, weil eine Bestätigung verloren gegangen ist. Ein Load Balancer könnte zwei Ereignisse über unterschiedliche Netzwerkpfade leiten, sodass das neuere zuerst ankommt. Ein Worker-Prozess könnte sterben, nachdem er in eine Datenbank geschrieben, aber bevor er das Erfolgsereignis veröffentlicht hat – nur damit ein zweiter Worker die Aufgabe übernimmt und seinen eigenen Fortschritt meldet. Wenn Ihr Frontend davon ausgeht, dass die neueste Nachricht die wahrste Nachricht ist, wird es einen Zustand zeichnen, der nie existiert hat. Benutzer werden sehen, wie ein „Abgeschlossen“-Badge zurück auf „In Bearbeitung“ springt, oder schlimmer noch, eine abgebrochene Aufgabe plötzlich wieder zum Leben erwacht. Geschwindigkeit ohne Reihenfolge ist nur Verwirrung mit einer höheren Bildrate.

Sequenznummern sind die wahre Uhr

Die Lösung sind strikte, monoton steigende Sequenznummern, die vom Producer generiert werden. Jede Operation, die den Zustand ändert, erhält eine Nummer, die genau um eins erhöht wird, ohne Lücken und ohne Rollbacks. Diese Nummer muss in derselben Transaktion wie das Ereignis selbst gespeichert werden. Wenn die Datenbankzeile aktualisiert wird, aber das Commit der Sequenz fehlschlägt, müssen beide zurückgerollt werden. Dies hält die logische Zeitlinie atomar mit der Zustandsänderung.

Event-IDs sind immer noch nützlich, aber sie lösen ein anderes Problem. Eine Event-ID identifiziert eine spezifische Payload, damit Sie diese deduplizieren können, wenn der Broker dieselbe Nachricht doppelt liefert. Eine Sequenznummer hingegen sagt Ihnen, wo diese Payload in der kausalen Kette steht. Sie deckt Lücken auf. Sie deckt die Reihenfolge auf. Ein Zeitstempel tut beides nicht. Uhren driften, NTP macht Rückwärtsschritte und virtuelle Maschinen pausieren. Verwenden Sie Zeitstempel nur für Anzeigezwecke, etwa „Vor 3 Minuten gestartet“, und niemals als Sortierschlüssel für die Geschäftslogik.

Wie der Client den Stream verarbeiten sollte

Sobald der Producer eine monotone Sequenz garantiert, erhält der Consumer einfache, harte Regeln. Wenn eine eingehende Sequenznummer kleiner oder gleich der zuletzt angewendeten Nummer ist, verwerfen Sie sie. Sie ist entweder ein Duplikat oder ein veralteter Nachzügler. Wenn die Sequenz genau um eins größer ist als die zuletzt angewendete Nummer, wenden Sie sie sofort an. Das ist der Happy Path. Wenn die Sequenz springt – sagen wir, Sie haben die 12 erwartet, aber die 15 erhalten – fehlt etwas. Puffern Sie das neue Ereignis und fragen Sie den Server nach einem Replay, beginnend mit der nächsten erwarteten Sequenz. Raten Sie nicht. Überspringen Sie nicht einfach, in der Hoffnung, dass die Lücke keine Rolle spielt.

Endzustände müssen als unwiderruflich behandelt werden. Sobald eine Aufgabe als abgeschlossen, fehlgeschlagen oder abgebrochen markiert wurde, sollte der Client alle nachfolgenden Zustandsänderungen für diese Operation ablehnen. Das klingt offensichtlich, bis man mit