Checkliste zur Zuverlässigkeit von Webhooks: Wiederholversuche, Idempotenz, Replay
Praktische Checkliste für Webhook-Zuverlässigkeit: Wiederholversuche, Idempotenz, Replay-Logs und Monitoring für eingehende und ausgehende Webhooks, wenn Partner ausfallen.

Warum Webhooks in echten Projekten unzuverlässig wirken
Ein Webhook ist erst einmal simpel: Ein System sendet eine HTTP-Anfrage an ein anderes, wenn etwas passiert. "Bestellung versandt", "Ticket aktualisiert", "Gerät offline". Im Grunde ist es eine Push-Benachrichtigung zwischen Apps, zugestellt über das Web.
In Demos wirken sie zuverlässig, weil der Happy Path schnell und sauber ist. In echten Projekten sitzen Webhooks zwischen Systemen, die du nicht kontrollierst: CRMs, Versanddienstleister, Helpdesks, Marketing-Tools, IoT-Plattformen oder sogar interne Apps anderer Teams. Abgesehen von Zahlungsdiensten fehlen dort oft ausgereifte Zustellgarantien, stabile Event-Schemata und konsistentes Retry-Verhalten.
Die ersten Anzeichen sind meist verwirrend:
- Duplikate (dasselbe Update kommt zweimal an)
- Fehlende Events (etwas hat sich geändert, aber du hast nichts gehört)
- Verzögerungen (ein Update kommt Minuten oder Stunden später)
- Events außerhalb der Reihenfolge (ein „closed“-Update kommt vor „opened“)
Unzuverlässige Drittsysteme lassen das zufällig wirken, weil Fehler nicht immer laut sind. Ein Provider kann timeouten und trotzdem deine Anfrage verarbeitet haben. Ein Load-Balancer kann eine Verbindung abbrechen, nachdem der Sender schon erneut gesendet hat. Oder das System geht kurz down und schickt dann auf einmal einen Schub alter Events.
Stell dir einen Versandpartner vor, der "delivered"-Webhooks sendet. Ein Tag ist dein Receiver 3 Sekunden langsam, also retryt der Sender. Du bekommst zwei Lieferungen, dein Kunde zwei E-Mails, und der Support ist verwirrt. Am nächsten Tag hat der Partner einen Ausfall und retryt nie, also kommt das "delivered" nicht an und dein Dashboard bleibt hängen.
Webhook-Zuverlässigkeit geht weniger um eine perfekte Anfrage als darum, für die unordentliche Realität zu entwerfen: Wiederholversuche, Idempotenz und die Möglichkeit, später wieder abzuspielen und zu prüfen, was passiert ist.
Die drei Bausteine: Retries, Idempotenz, Replay
Webhooks kommen in zwei Richtungen. Inbound-Webhooks sind Anfragen, die du von jemand anderem erhältst (ein Zahlungsanbieter, CRM, Versandtool). Outbound-Webhooks sind Anfragen, die du an deinen Kunden oder Partner sendest, wenn sich in deinem System etwas ändert. Beide können aus Gründen fehlschlagen, die nichts mit deinem Code zu tun haben.
Retries sind das, was nach einem Fehler passiert. Ein Sender retryt vielleicht wegen eines Timeouts, eines 500-Errors, einer abgebrochenen Verbindung oder keiner schnellen Antwort. Gute Retries sind erwartetes Verhalten, kein seltener Spezialfall. Ziel ist, das Event durchzubekommen, ohne den Receiver zu überfluten oder doppelte Seiteneffekte zu erzeugen.
Idempotenz macht Duplikate ungefährlich. Sie bedeutet: „Führe es einmal aus, auch wenn es zweimal ankommt“. Wenn derselbe Webhook erneut kommt, erkennst du das und gibst eine Erfolgsmeldung zurück, ohne die Geschäftsaktion ein zweites Mal auszuführen (z. B. keine zweite Rechnung erstellen).
Replay ist dein Wiederherstellungsknopf. Es ist die Fähigkeit, vergangene Events bewusst und kontrolliert erneut zu verarbeiten, nachdem du einen Fehler behoben oder ein Partner einen Ausfall hatte. Replay unterscheidet sich von Retries: Retries sind automatisch und unmittelbar, Replay ist absichtlich und passiert oft Stunden oder Tage später.
Wenn du Webhook-Zuverlässigkeit erreichen willst, setze ein paar einfache Ziele und entwerfe um sie herum:
- Keine verlorenen Events (du kannst immer finden, was angekommen oder was du zu senden versucht hast)
- Sichere Duplikate (Retries und Replays führen nicht zu Doppelbelastungen, Doppel-Erstellungen oder doppelten E-Mails)
- Klare Audit-Trail (du kannst schnell beantworten: „Was ist passiert?“)
Praktisch unterstützt du alle drei, indem du jeden Webhook-Versuch mit Status und einem eindeutigen Idempotenz-Schlüssel speicherst. Viele Teams bauen dafür eine kleine "Webhook-Inbox/Outbox"-Tabelle.
Inbound-Webhooks: Ein wiederverwendbarer Receiver-Flow
Die meisten Webhook-Probleme entstehen, weil Sender und Receiver auf unterschiedlichen Uhren laufen. Deine Aufgabe als Receiver ist vorhersehbar zu sein: schnell bestätigen, aufzeichnen, was angekommen ist, und sicher verarbeiten.
"Akzeptieren" vom "Arbeiten" trennen
Beginne mit einem Flow, der die HTTP-Anfrage kurz hält und die eigentliche Arbeit woanders ablegt. Das reduziert Timeouts und macht Retries weniger schmerzhaft.
- Acknowledge schnell. Gib ein 2xx zurück, sobald die Anfrage akzeptabel ist.
- Prüfe das Nötigste. Validere Content-Type, Pflichtfelder und Parsing. Wenn der Webhook signiert ist, verifiziere die Signatur hier.
- Persistiere das rohe Event. Speichere Body plus die Header, die du später brauchst (Signatur, Event-ID), zusammen mit Zeitstempel und einem Status wie "received".
- Queue die Arbeit. Erstelle einen Job für die Hintergrundverarbeitung und gib dann dein 2xx zurück.
- Verarbeite mit klaren Ergebnissen. Markiere das Event erst als "processed", nachdem Seiteneffekte erfolgreich waren. Wenn es fehlschlägt, zeichne den Grund und ob es erneut versucht werden soll.
Wie "schnell antworten" aussieht
Ein realistisches Ziel ist, in unter einer Sekunde zu antworten. Wenn der Sender einen bestimmten Code erwartet, nutze ihn (viele akzeptieren 200, einige bevorzugen 202). Gib nur 4xx zurück, wenn der Sender nicht retryen soll (z. B. ungültige Signatur).
Beispiel: Ein "customer.created"-Webhook kommt, während deine Datenbank unter Last steht. Mit diesem Flow speicherst du das rohe Event, legst es in die Queue und antwortest 2xx. Dein Worker kann später erneut versuchen, ohne dass der Sender nochmal senden muss.
Inbound-Sicherheitsprüfungen, die Zustellung nicht kaputtmachen
Sicherheitsprüfungen lohnen sich, aber das Ziel ist einfach: blockiere schlechten Traffic, ohne echte Events zu blockieren. Viele Zustellprobleme entstehen, weil Receiver zu strikt sind oder den falschen Response zurückgeben.
Beginne damit, den Sender zu verifizieren. Bevorzuge signierte Requests (HMAC-Signatur-Header) oder ein Shared-Secret-Token im Header. Verifiziere davor und fehlschlage schnell, wenn es fehlt oder falsch ist.
Sei vorsichtig mit Statuscodes, weil sie Retries steuern:
- Gib 401/403 bei Auth-Fehlern zurück, damit der Sender nicht ewig retryt.
- Gib 400 bei fehlerhaftem JSON oder fehlenden Pflichtfeldern zurück.
- Gib 5xx nur, wenn dein Service vorübergehend nicht akzeptieren oder verarbeiten kann.
IP-Allowlists helfen, aber nur, wenn der Provider stabile, dokumentierte IP-Bereiche hat. Wenn deren IPs oft wechseln (oder sie große Cloud-Pools nutzen), können Allowlists echte Webhooks stillschweigend verwerfen und du bemerkst es erst viel später.
Wenn der Provider Zeitstempel und eine unique Event-ID mitsendet, kannst du Replay-Schutz hinzufügen: lehne Nachrichten ab, die zu alt sind, und tracke kürzliche IDs, um Duplikate zu erkennen. Halte das Zeitfenster klein, aber mit einer Gnadenfrist, damit Uhrabweichungen keine gültigen Requests blockieren.
Eine Receiver-freundliche Sicherheits-Checkliste:
- Validere Signatur oder Shared Secret bevor du große Payloads parst.
- Setze eine maximale Body-Größe und ein kurzes Request-Timeout durch.
- Nutze 401/403 für Auth-Fehler, 400 für fehlerhaftes JSON und 2xx für akzeptierte Events.
- Wenn du Zeitstempel prüfst, erlaube ein kleines Gnadenfenster (z. B. ein paar Minuten).
Für das Logging: Halte eine Audit-Trail ohne sensible Daten ewig zu speichern. Speichere Event-ID, Sender-Name, Empfangszeit, Verifikationsergebnis und einen Hash des rohen Bodys. Wenn du Payloads speichern musst, setze eine Aufbewahrungsfrist und maskiere Felder wie E-Mails, Tokens oder Zahlungsdaten.
Retries, die helfen statt schaden
Retries sind gut, wenn sie einen kurzen Hänger in eine erfolgreiche Zustellung verwandeln. Sie sind schädlich, wenn sie Traffic vervielfachen, echte Bugs verbergen oder Duplikate erzeugen. Der Unterschied ist, klare Regeln dafür zu haben, was erneut versucht wird, wie die Versuche gestaffelt sind und wann gestoppt wird.
Als Basis: retry nur bei Fehlern, bei denen der Receiver später wahrscheinlich erfolgreich sein wird. Ein nützliches Mentalmodell: retry bei "temporären" Fehlern, nicht bei "du hast etwas Falsches gesendet".
Praktische HTTP-Ergebnisse:
- Retry: Netzwerk-Timeouts, Verbindungsfehler und HTTP 408, 429, 500, 502, 503, 504
- Nicht retryen: HTTP 400, 401, 403, 404, 422
- Kommt darauf an: HTTP 409 (manchmal "duplicate", manchmal echter Konflikt)
Die Staffelung ist wichtig. Nutze exponentielles Backoff mit Jitter, damit du keinen Retry-Sturm erzeugst, wenn viele Events gleichzeitig scheitern. Beispiel: warte 5s, 15s, 45s, 2m, 5m und füge jeweils eine kleine zufällige Verzögerung hinzu.
Setze außerdem ein maximales Retry-Fenster und einen klaren Cutoff. Übliche Optionen sind "versuche bis zu 24 Stunden" oder "nicht mehr als 10 Versuche". Danach ist es ein Recovery-Problem, kein Zustellungsproblem.
Damit das im Alltag funktioniert, sollte dein Event-Record erfassen:
- Anzahl der Versuche
- Letzter Fehler
- Nächster Versuchstermin
- Finaler Status (inklusive Dead-Letter-Zustand, wenn du aufhörst zu retryen)
Dead-Letter-Items sollten einfach zu inspizieren und sicher wieder abspielbar sein, nachdem das zugrunde liegende Problem behoben ist.
Idempotenz-Muster, die in der Praxis funktionieren
Idempotenz bedeutet, dass du dasselbe Webhook mehrfach verarbeiten kannst, ohne zusätzliche Seiteneffekte zu erzeugen. Das ist eine der schnellsten Methoden, die Zuverlässigkeit zu verbessern, denn Timeouts und Retries passieren selbst dann, wenn niemand etwas falsch macht.
Wähle einen Schlüssel, der stabil bleibt
Wenn der Provider dir eine Event-ID gibt, verwende sie. Das ist die sauberste Option.
Wenn keine Event-ID vorhanden ist, baue einen eigenen Schlüssel aus stabilen Feldern, zum Beispiel als Hash aus:
- provider-name + event-type + resource-id + timestamp, oder
- provider-name + message-id
Speichere den Schlüssel plus ein paar Metadaten (Empfangszeit, Provider, Event-Typ und Ergebnis).
Regeln, die sich gewöhnlich bewähren:
- Behandle den Schlüssel als erforderlich. Wenn du keinen bauen kannst, quaranteiniere das Event statt zu raten.
- Lege TTLs auf die Schlüssel (z. B. 7 bis 30 Tage), damit die Tabelle nicht ewig wächst.
- Speichere auch das Verarbeitungsergebnis (success, failed, ignored), damit Duplikate konsistent beantwortet werden.
- Setze eine Unique-Constraint auf den Schlüssel, damit zwei parallele Requests nicht beide die Aktion ausführen.
Mach auch die Geschäftsaktion idempotent
Selbst mit einer guten Schlüssel-Tabelle müssen reale Operationen sicher sein. Beispiel: Ein "create order"-Webhook sollte keinen zweiten Auftrag anlegen, wenn der erste Versuch nach dem DB-Insert timed out hat. Verwende natürliche Geschäftskennungen (external_order_id, external_user_id) und Upsert-Pattern.
Out-of-Order-Events sind üblich. Wenn du "user_updated" bevor "user_created" erhältst, lege eine Regel fest wie: "wende Änderungen nur an, wenn event_version neuer ist" oder "aktualisiere nur, wenn updated_at später ist als das, was wir haben".
Duplikate mit unterschiedlichen Payloads sind am schwierigsten. Entscheide vorher, wie du damit umgehst:
- Wenn der Schlüssel passt, aber die Payload unterscheidet sich stark: behandle es als Provider-Bug und alert.
- Wenn der Schlüssel passt und sich nur unwichtige Felder unterscheiden: ignoriere die Unterschiede.
- Wenn du dem Provider nicht trauen kannst, wechsle zu einem abgeleiteten Schlüssel basierend auf dem kompletten Payload-Hash und behandle Konflikte als neue Events.
Das Ziel ist einfach: Eine reale Änderung sollte ein reales Ergebnis erzeugen, selbst wenn du die Nachricht dreimal siehst.
Replay-Tools und Audit-Logs für die Wiederherstellung
Wenn ein Partner-System unzuverlässig ist, geht es bei Zuverlässigkeit weniger um perfekte Zustellung als um schnelle Wiederherstellung. Ein Replay-Tool verwandelt "wir haben Events verloren" in eine Routine-Reparatur statt in eine Krise.
Beginne mit einem Event-Log, das den Lebenszyklus jedes Webhooks verfolgt: received, processed, failed oder ignored. Halte es durchsuchbar nach Zeit, Event-Typ und Korrelations-ID, damit Support schnell beantworten kann: "Was ist mit Bestellung 18432 passiert?"
Speichere für jedes Event genug Kontext, um dieselbe Entscheidung später erneut auszuführen:
- Roh-Payload und Key-Header (Signatur, Event-ID, Timestamp)
- Normalisierte Felder, die du extrahiert hast
- Verarbeitungsresultat und Fehlermeldung (falls vorhanden)
- Die Workflow- oder Mapping-Version, die zum Zeitpunkt der Verarbeitung verwendet wurde
- Zeitstempel für Empfang, Start, Ende
Mit diesen Daten fügst du eine "Replay"-Aktion für fehlgeschlagene Events hinzu. Der Button ist weniger wichtig als die Schutzmaßnahmen. Ein guter Replay-Flow zeigt den vorherigen Fehler, was beim Replay passieren wird und ob das Event sicher erneut ausgeführt werden kann.
Schutzmaßnahmen, die unbeabsichtigte Schäden verhindern:
- Erfordere eine Begründung vor dem Replay
- Beschränke Replay-Berechtigungen auf eine kleine Rolle
- Führe dieselben Idempotenz-Prüfungen wie beim ersten Versuch durch
- Rate-limit Replays, um während Vorfällen keinen neuen Spike zu erzeugen
- Optional: Dry-Run-Modus, der validiert ohne Änderungen zu schreiben
Vorfälle betreffen oft mehr als ein Event; unterstütze Replay nach Zeitbereich (z. B. "replay alle fehlgeschlagenen Events zwischen 10:05 und 10:40"). Logge, wer was wann und warum replayt hat.
Outbound-Webhooks: Ein sendender Flow, den du auditieren kannst
Outbound-Webhooks schlagen aus banalen Gründen fehl: ein langsamer Receiver, ein kurzzeitiger Ausfall, ein DNS-Hänger oder ein Proxy, der lange Requests verwirft. Zuverlässigkeit entsteht, wenn du jeden Sendeversuch als nachverfolgbaren, wiederholbaren Job behandelst, nicht als einmaligen HTTP-Call.
Ein Sender-Flow, der vorhersehbar bleibt
Gib jedem Event eine stabile, eindeutige Event-ID. Diese ID sollte über Retries, Replays und sogar Service-Restarts hinweg gleich bleiben. Wenn du pro Versuch eine neue ID generierst, erschwerst du Deduplizierung für den Receiver und die Auditbarkeit für dich.
Signiere jede Anfrage und füge einen Timestamp bei. Der Timestamp hilft Receivern, sehr alte Requests abzulehnen; die Signatur beweist, dass die Payload unterwegs nicht verändert wurde. Halte die Signaturregeln simpel und konsistent, damit Partner sie ohne Rätsel umsetzen können.
Tracke Zustellungen pro Endpoint, nicht nur pro Event. Wenn du dasselbe Event an drei Kunden sendest, braucht jedes Ziel seine eigene Attempt-Historie und seinen finalen Status.
Ein praktikabler Flow, den die meisten Teams umsetzen können:
- Erstelle einen Event-Record mit Event-ID, Endpoint-ID, Payload-Hash und Initial-Status.
- Sende die HTTP-Anfrage mit Signatur, Timestamp und einem Idempotency-Key-Header.
- Zeichne jeden Versuch auf (Startzeit, Endzeit, HTTP-Status, kurze Fehlermeldung).
- Retry nur bei Timeouts und 5xx-Antworten, mit exponentiellem Backoff und Jitter.
- Stoppe nach klarer Grenze (max. Versuche oder max. Alter) und markiere es dann als fehlgeschlagen zur Überprüfung.
Dieser Idempotency-Key-Header ist wichtig, auch wenn du Sender bist. Er gibt dem Receiver eine einfache Möglichkeit zur Deduplizierung, falls der erste Versuch verarbeitet wurde, aber dein Client die 200-Antwort nie erhalten hat.
Mach Fehler sichtbar. "Failed" sollte nicht "verloren" heißen, sondern "pausiert mit genug Kontext zum sicheren Replay".
Beispiel: ein fehleranfälliges Partner-System und saubere Wiederherstellung
Deine Support-App sendet Ticket-Updates an ein Partner-System, damit deren Agents denselben Status sehen. Jedes Mal, wenn ein Ticket sich ändert (zugewiesen, Priorität geändert, geschlossen), postest du ein Webhook-Event wie ticket.updated.
Eines Nachmittags beginnt der Partner-Endpoint zu timeouten. Dein erster Zustellversuch wartet, erreicht dein Timeout-Limit und du behandelst es als "unbekannt" (es könnte sie erreicht haben oder auch nicht). Eine gute Retry-Strategie versucht dann mit Backoff erneut statt jede Sekunde neue Requests zu feuern. Das Event bleibt in einer Queue mit derselben Event-ID, und jeder Versuch wird protokolliert.
Das Schmerzliche: Wenn du keine Idempotenz hast, verarbeitet der Partner eventuell Duplikate. Versuch #1 könnte sie erreicht haben, aber ihre Antwort kam nie zurück. Versuch #2 kommt später an und erzeugt eine zweite "Ticket closed"-Aktion, schickt zwei E-Mails oder legt zwei Timeline-Einträge an.
Mit Idempotenz enthält jede Zustellung einen Idempotency-Key, der aus dem Event abgeleitet wird (oft einfach die Event-ID). Der Partner speichert diesen Schlüssel für eine Zeit und antwortet mit "bereits verarbeitet" bei Wiederholungen. Du musst nicht raten.
Wenn der Partner wieder verfügbar ist, behebst du das wirklich fehlende Update (z. B. eine Prioritätsänderung während des Ausfalls) per Replay. Du wählst das Event aus deinem Audit-Log und spielst es einmal erneut mit derselben Payload und demselben Idempotency-Key ab — sicher, selbst wenn sie es schon hatten.
Während des Vorfalls sollten deine Logs die Geschichte klar machen:
- Event-ID, Ticket-ID, Event-Typ und Payload-Version
- Versuchszahl, Zeitstempel und nächster Retry-Termin
- Timeout vs. non-2xx-Antwort vs. Erfolg
- Gesendeter Idempotency-Key und ob der Partner "duplicate" meldete
- Ein Replay-Log, wer es re-played hat und das finale Ergebnis
Häufige Fehler und Fallen, die du vermeiden solltest
Die meisten Webhook-Vorfälle entstehen nicht durch einen großen Bug, sondern durch kleine Entscheidungen, die bei Traffic-Spitzen oder Partner-Ausfällen die Zuverlässigkeit still zerlegen.
Fallen, die in Postmortems auftauchen:
- Langsame Arbeit im Request-Handler (DB-Schreibungen, API-Calls, Datei-Uploads), bis der Sender timeoutet und retryt
- Davon auszugehen, dass Provider nie Duplikate senden, und dadurch doppelt berechnen, doppelt anlegen oder doppelte E-Mails versenden
- Falsche Statuscodes zurückgeben (200, obwohl du das Event nicht akzeptiert hast, oder 500 für fehlerhafte Daten, die nie durch Retries heilen werden)
- Ohne Korrelations-ID, Event-ID oder Request-ID deployen und dann Stunden damit verbringen, Logs und Kundenberichte abzugleichen
- Ewig retryen, was ein Backlog aufbaut und einen Partner-Ausfall in deinen eigenen verwandelt
Eine einfache Regel hilft: schnell bestätigen, dann sicher verarbeiten. Validere nur, was du brauchst, um zu entscheiden, ob du das Event akzeptierst, speichere es und erledige den Rest asynchron.
Statuscodes sind wichtiger, als die meisten erwarten:
- Nutze 2xx nur, wenn du das Event gespeichert (oder gequeued) hast und zuversichtlich bist, dass es bearbeitet wird.
- Nutze 4xx für ungültige Eingaben oder fehlgeschlagene Auth, damit der Sender aufhört zu retryen.
- Nutze 5xx nur für temporäre Probleme auf deiner Seite.
Setze eine Retry-Grenze. Höre nach einem festen Fenster (z. B. 24 Stunden) oder einer festen Anzahl von Versuchen auf und markiere das Event als "needs review", damit ein Mensch entscheiden kann, was replayt werden soll.
Kurze Checkliste und nächste Schritte
Webhook-Zuverlässigkeit besteht größtenteils aus wiederholbaren Gewohnheiten: schnell akzeptieren, aggressiv deduplizieren, mit Bedacht retryen und einen Replay-Pfad offenhalten.
Inbound (Receiver) Schnellchecks
- Gib ein schnelles 2xx zurück, sobald die Anfrage sicher gespeichert ist (langsames Arbeiten asynchron ausführen).
- Speichere genug vom Event, um zu beweisen, was du empfangen hast (und später debuggen zu können).
- Fordere einen Idempotenz-Schlüssel (oder leite einen aus Provider + Event-ID ab) und erzwinge ihn in der Datenbank.
- Nutze 4xx für falsche Signaturen oder ungültiges Schema; 5xx nur für echte Serverprobleme.
- Tracke Verarbeitungsstatus (received, processed, failed) plus die letzte Fehlermeldung.
Outbound (Sender) Schnellchecks
- Vergib eine eindeutige Event-ID pro Event und behalte sie über Versuche hinweg bei.
- Signiere jede Anfrage und füge einen Timestamp hinzu.
- Definiere eine Retry-Policy (Backoff, max. Versuche, wann aufgehört wird) und halte dich daran.
- Tracke pro Endpoint: letzter Erfolg, letzter Fehler, aufeinanderfolgende Fehler, nächster Retry-Zeitpunkt.
- Logge jeden Versuch mit genug Details für Support und Audits.
Für den Betrieb: Entscheide vorher, was du replayen wirst (einzelnes Event, Batch nach Zeitbereich/Status oder beides), wer es darf und wie deine Dead-Letter-Review-Routine aussieht.
Wenn du diese Teile bauen willst, ohne alles von Hand zu verdrahten, kann eine No-Code-Plattform wie AppMaster praktisch sein: Du modellierst Webhook-Inbox/Outbox-Tabellen in PostgreSQL, setzt Retry- und Replay-Flows im visuellen Business Process Editor um und stellst ein internes Admin-Panel bereit, um fehlgeschlagene Events zu durchsuchen und erneut auszuführen, wenn Partner unzuverlässig werden.
FAQ
Webhooks sitzen zwischen Systemen, die du nicht kontrollierst. Deshalb erbst du deren Timeouts, Ausfälle, Retries und Schema-Änderungen. Selbst bei korrektem eigenen Code siehst du Duplikate, fehlende Events, Verzögerungen und aus dem Tritt geratene Reihenfolgen.
Plane von Anfang an für Retries und Duplikate. Speichere jedes eingehende Event, antworte mit einem schnellen 2xx, sobald es sicher aufgezeichnet ist, und verarbeite asynchron mit einem Idempotenz-Schlüssel, sodass wiederholte Zustellungen keine Seiteneffekte verdoppeln.
Du solltest schnell bestätigen, nachdem die grundlegende Validierung und Speicherung erfolgt ist — normalerweise in unter einer Sekunde. Wenn du langsame Arbeit im Request ausführst, timeouten Sender und retryen, was Duplikate und komplexere Vorfälle erzeugt.
Idempotenz bedeutet: führe die Geschäftsaktion nur einmal aus, auch wenn die Nachricht mehrfach ankommt. Du erzwingst das mit einem stabilen Idempotenz-Schlüssel (oft die Event-ID des Providers), indem du ihn speicherst und bei Duplikaten Erfolg zurückgibst, ohne die Aktion erneut auszuführen.
Verwende die Event-ID des Providers, wenn vorhanden. Falls nicht, leite einen Schlüssel aus stabilen Feldern ab. Vermeide Felder, die sich zwischen Versuchen ändern können. Wenn kein verlässlicher Schlüssel gebaut werden kann, quarantäne das Event zur Prüfung, statt zu raten.
Gib 4xx bei Problemen zurück, die der Sender nicht durch erneutes Senden beheben kann (z. B. fehlende Authentifizierung oder fehlerhaftes Schema). Verwende 5xx nur bei vorübergehenden Problemen auf deiner Seite. Sei konsistent — Statuscodes steuern oft, ob der Sender retryt.
Retry bei Timeouts, Verbindungsfehlern und temporären Serverantworten wie 408, 429 und 5xx. Nutze exponentielles Backoff mit Jitter und eine klare Grenze, etwa eine maximale Anzahl von Versuchen oder ein maximales Alter, danach markiere das Event als "zur Überprüfung".
Replay ist das kontrollierte, absichtliche Neuausführen vergangener Events, nachdem ein Fehler behoben oder ein Ausfall vorbei ist. Retries sind automatisch und unmittelbar. Guter Replay braucht ein Event-Log, sichere Idempotenz-Prüfungen und Schutzmaßnahmen, damit keine Arbeit versehentlich verdoppelt wird.
Gehe davon aus, dass Events außer Reihenfolge ankommen können, und lege eine Regel fest, die zu deinem Business passt. Gängig ist: wende ein Update nur an, wenn event_version oder timestamp neuer ist als das aktuell gespeicherte, damit verspätete Nachrichten keinen neueren Zustand überschreiben.
Baue eine einfache Inbox/Outbox-Tabelle und eine kleine Admin-Ansicht, um fehlgeschlagene Events zu suchen, zu inspizieren und wieder abzuspielen. Mit AppMaster kannst du diese Tabellen in PostgreSQL modellieren, Dedupe-, Retry- und Replay-Flows im Business Process Editor abbilden und ein internes Panel für den Support bereitstellen, ohne alles von Hand zu coden.


