Zum Hauptinhalt springen
Zurück zum Blog
Technologie6 Min. Lesezeit02.08.2026Max Fey

Der alte Status gewinnt: warum Webhooks nicht in der Reihenfolge ankommen

Webhooks kommen nicht zwangsläufig in der Reihenfolge an, in der sie gesendet wurden. Zwei Meldungen im Sekundenabstand überholen sich, der ältere Wert bleibt stehen, und im Log sieht alles grün aus. Was dagegen hilft und wie Sie prüfen, ob es Sie schon getroffen hat.

Der Fahrer hatte zugestellt, dann war das Paket wieder unterwegs

Ein Kontraktlogistiker aus dem Rheinland hat im Frühjahr die Statusmeldungen seines Transportdienstleisters an das eigene Kundenportal angebunden. Pro Sendung schickt der Dienstleister einen Webhook: angenommen, im Umschlag, in Zustellung, zugestellt. Der Workflow nimmt die Meldung entgegen und schreibt den Status in die Sendungstabelle.

Nach drei Wochen kam die erste Beschwerde. Ein Kunde hatte im Portal gesehen, dass seine Lieferung zugestellt war, und zwanzig Minuten später stand dort wieder "in Zustellung". Der Disponent konnte den Fehler nicht nachstellen, weil die Sendung beim Dienstleister sauber auf "zugestellt" stand.

Gemeldet hatte der Dienstleister korrekt, und zwar in der richtigen Reihenfolge. Die Meldungen kamen nur nicht in dieser Reihenfolge an.

Reihenfolge ist keine Eigenschaft von Webhooks

In fast jeder Webhook-Dokumentation steht ein Satz dazu, dass die Reihenfolge der Zustellung nicht garantiert ist. Stripe schreibt es hin, Shopify auch, HubSpot ebenfalls. Gelesen wird der Satz selten, weil er beim Testen nie eine Rolle spielt.

Die Gründe dafür sehen einzeln harmlos aus. Das sendende System arbeitet seine Warteschlange mit mehreren Prozessen parallel ab, und welcher zuerst fertig wird, entscheidet die Auslastung. Schlägt eine Zustellung fehl, etwa weil Ihr Endpunkt zwei Sekunden zu lange gebraucht hat, wird sie eine halbe Minute später wiederholt, und in dieser halben Minute geht das nächste Event durch. Auf Ihrer Seite verarbeiten Make und n8n eingehende Aufrufe ebenfalls nebeneinander, sodass der zweite Lauf den ersten überholen kann.

Zwei Events, die in der Quelle Stunden auseinanderliegen, treffen praktisch immer in der richtigen Folge ein. Bei Sekundenabstand ist es Zufall. Und Sekundenabstände entstehen ständig: jemand legt einen Datensatz an und korrigiert sofort den Tippfehler, ein Fahrer scannt zweimal hintereinander, ein Sammellauf meldet zehn Positionen auf einen Schlag.

Der Workflow schreibt stur, was gerade hereinkommt

Der Standardaufbau kennt keine Reihenfolge. Webhook rein, Felder zuordnen, Datensatz aktualisieren. Wer zuletzt schreibt, gewinnt. Trägt der letzte Schreibvorgang das ältere Event, bleibt der alte Wert stehen, und zwar dauerhaft, weil kein weiteres Event mehr kommt, das ihn korrigieren würde.

Betroffen ist jedes Feld, das einen Zustand abbildet statt einer Historie: Sendungsstatus, Auftragsstatus, Lieferadresse, Zahlungsstatus, Bestandsmenge.

Beim Bestand wird es unangenehm. Meldet das Lagersystem absolute Zahlen, erst 40 Stück, nach dem Kommissionieren 12, und die 40 trifft als Letzte ein, dann steht im Shop ein Bestand, den es nicht gibt. Verkauft wird er trotzdem. Auffällig wird die Sache beim Packen.

Die Empfangszeit ist der falsche Zeitstempel

Viele Workflows stempeln das Event beim Empfang, mit `now()` in Make oder `$now` in n8n. Damit ist jedes eintreffende Event per Definition das neueste, und die Prüfung, die man eingebaut zu haben glaubt, prüft nichts.

Der Zeitstempel muss aus der Nutzlast kommen. Die meisten Anbieter liefern ihn mit, unter Namen wie `occurred_at`, `event_time` oder `updated_at`. Fehlt er, ist das ein Argument dafür, dem Push nicht zu vertrauen und stattdessen abzurufen.

Vergleichbar sind Zeitstempel erst, wenn sie in derselben Zone liegen. Wir rechnen sie vor dem Vergleich nach UTC um, sonst stimmt das Ergebnis zweimal im Jahr nicht.

Drei Wege, das abzustellen

Das Zielsystem bekommt ein zusätzliches Feld, meist `letztes_ereignis_am`. Der Workflow liest den Datensatz, vergleicht den gespeicherten Wert mit dem Zeitstempel aus der Nutzlast und schreibt nur, wenn das Event neuer ist. Ältere Meldungen wandern in ein Protokoll statt in den Datensatz. Das kostet zwei zusätzliche Module und deckt den größten Teil der Fälle ab.

Wo kein brauchbarer Zeitstempel ankommt, arbeiten wir mit erlaubten Übergängen. Jeder Status bekommt einen Rang, geschrieben wird nur nach oben. Von "zugestellt" zurück auf "in Zustellung" geht es nicht, außer jemand storniert von Hand, und dafür gibt es einen eigenen Weg.

Am stabilsten ist die dritte Variante: Das Event ist nur noch die Türklingel. Wenn es klingelt, ruft der Workflow die Sendung per API ab und schreibt den Zustand, den das Quellsystem in diesem Moment meldet. Die Reihenfolge wird damit egal. Bezahlt wird das mit einem zusätzlichen Aufruf pro Event, was bei knappen Rate Limits gegen die Variante spricht.

Eine Einschränkung gilt für alle drei. Laufen zwei Ausführungen zur selben Sendung gleichzeitig, kann der Vergleich ins Leere gehen, weil beide denselben alten Wert gelesen haben, bevor einer geschrieben hat. Wer das ausschließen muss, braucht eine bedingte Aktualisierung im Zielsystem oder eine Verarbeitung, die pro Datensatz nur einen Lauf gleichzeitig zulässt.

Das Update, das vor dem Anlegen ankommt

Der Fall, den wir am häufigsten sehen, hat mit Status nichts zu tun. Ein Quellsystem meldet "angelegt" und kurz darauf "geändert". Überholt die zweite Meldung die erste, sucht der Workflow einen Datensatz, den es noch nicht gibt. Je nach Bauart legt er dann einen an oder bricht ab. Trifft danach "angelegt" ein, steht das Duplikat im System.

Dagegen hilft ein Upsert über die ID des Quellsystems statt der Kombination aus Suchen und Anlegen. Kann das Zielsystem kein Upsert, verzögern wir den Lauf um ein paar Sekunden und suchen ein zweites Mal, bevor überhaupt etwas angelegt wird.

Im Test tritt das nie auf

Von Hand ausgelöste Events überholen sich nicht. Deshalb schicken wir vor dem Livegang zwei Meldungen absichtlich vertauscht an den Endpunkt, mit den Zeitstempeln in der ursprünglichen Folge, und sehen nach, welcher Status danach im Zielsystem steht. Denselben Aufruf zweimal zu senden gehört in denselben Testlauf.

Ob es Sie schon getroffen hat

Protokolliert Ihr Workflow jede Ausführung, suchen Sie nach Datensätzen, bei denen ein späterer Lauf einen älteren Ereigniszeitstempel verarbeitet hat. Ohne Protokoll bleibt die Suche nach Zuständen, die rückwärts gelaufen sind: eine Sendung, die nach der Zustellung wieder unterwegs war, ein Auftrag, der nach dem Abschluss wieder offen stand.

Bei dem Logistiker waren es 61 Sendungen in sechs Wochen, also vier von tausend. Das klingt nach wenig, bis man es in Telefonaten rechnet. 61 Kunden haben im Portal etwas anderes gesehen als der Disponent, den sie danach angerufen haben.

Der Workflow vergleicht seitdem Zeitstempel und legt ältere Meldungen in eine eigene Tabelle. In den ersten zwei Wochen sind dort 74 Zeilen gelandet.

#Webhooks#Reihenfolge#Event-Verarbeitung#Statusmeldungen#Upsert#Datenqualität#Make#n8n