Wie kann ich doppelte Workflow-Ausführungen verhindern, wenn ein Webhook mehrmals ausgelöst wird?
Welche Fehlermeldung erhalten Sie (falls vorhanden)?
Webhook Set HTTP Request Airtable Ich bin mir bewusst, dass Stripe fehlgeschlagene Anfragen wiederholt, aber auch erfolgreiche kommen manchmal zweimal an. Wie kann ich sicherstellen, dass jedes Ereignis nur einmal verarbeitet wird?
Bitte teilen Sie Ihren Workflow mit
(Wählen Sie die Knoten auf der Canvas aus und verwenden Sie die Tastenkombinationen CMD+C/STRG+C und CMD+V/STRG+V, um den Workflow zu kopieren und einzufügen.)
Geben Sie die Ausgabe des letzten Knotens an
Ich verwende einen Webhook-Knoten, der Ereignisse von Stripe empfängt. Gelegentlich wird das gleiche Ereignis mehrmals zugestellt, was dazu führt, dass mein Workflow doppelte Bestellungen verarbeitet
Informationen zu Ihrem n8n-Setup
- n8n-Version: 1.123
- Datenbank (Standard: SQLite): PostgreSQL
- n8n EXECUTIONS_PROCESS-Einstellung (Standard: own, main):
- n8n wird ausgeführt über (Docker, npm, n8n cloud, Desktop-App):
- Betriebssystem:
Hallo @Fatoki_Alfred
Jedes Stripe-Event enthält eine eindeutige id (z. B. evt_1Nabc...). Um sicherzustellen, dass jedes Event nur einmal verarbeitet wird, solltest du diese IDs in einer dedizierten Tabelle „verarbeitete Events
Hi @Fatoki_Alfred
n8n hat einen integrierten Remove Duplicates-Knoten, der dies ohne benutzerdefinierte Tabelle oder Abfrage durchführt. Platziere ihn direkt nach dem Webhook-Knoten und stelle Operation auf „Remove Items Processed in Previous Executions
Als Ergänzung zu den obigen Antworten: Der Punkt, der oft übersehen wird, ist das Race Condition-Problem. Wenn Stripe dieselbe evt_id parallel liefert, können zwei Workflows die Deduplizierungsprüfung BESTEHEN, bevor einer die ID speichert — und beide laufen weiter. Der Knoten Remove Duplicates löst den seriellen Fall, ist aber unter Parallelität nicht atomar.
Um wirklich sicherzustellen, dedupliziert im eigenen Datenbank: Erstellen Sie die Spalte mit UNIQUE-Constraint (z. B. stripe_event_id TEXT UNIQUE) und direkt nach dem Webhook einen Postgres-Knoten mit INSERT … ON CONFLICT (stripe_event_id) DO NOTHING RETURNING id. Wenn RETURNING leer zurückkommt, handelt es sich um eine doppelte Zustellung → stoppen Sie den Fluss dort (ein IF prüft, ob eine Zeile zurückgegeben wurde). Die Datenbank garantiert Atomarität, daher auch bei zwei gleichzeitigen Zustellungen: nur eine gewinnt das INSERT.
Zwei zusätzliche Dinge, die das Problem an der Quelle stark reduzieren: (1) Antworte Stripe so schnell wie möglich mit 200 (nutze den Webhook im Modus Respond Immediately oder einen Knoten Respond to Webhook am Anfang) — Timeouts führen zu Retry-Versuchen von Stripe, und dort entstehen viele „Duplikate"; und (2) verarbeite die Bestellung erst nach erfolgreichem INSERT der Kontrolle. So ist die Event-ID dein echter Idempotenzschlüssel, und die Bestelllogik läuft niemals zweimal.
Hi @Fatoki_Alfred
Stripe wiederholt Webhook-Zustellungen absichtlich, daher sind doppelte Ereignisse zu erwarten. Der empfohlene Ansatz besteht darin, deinen Workflow idempotent zu gestalten, anstatt anzunehmen, dass jeder Webhook eindeutig ist.
Die einfachste Lösung besteht darin, die Stripe-Event-ID zu speichern, bevor die Verarbeitung beginnt. Am Anfang des Workflows:
- Extrahiere event.id.
- Frage deine Datenbank (oder den Data Store) nach dieser ID ab.
Falls sie bereits vorhanden ist, stoppe den Workflow.
Andernfalls speichere die ID und fahre mit der Verarbeitung fort.
Die Verwendung eines IF-Knotens vor deiner Geschäftslogik ist normalerweise ausreichend.
Falls du in Airtable oder eine andere Datenbank schreibst, solltest du event.id als eindeutiges Feld festlegen, damit Duplikate automatisch abgelehnt werden.
Behandeln Sie Stripe-Webhooks als At-Least-Once-Delivery und machen Sie den Workflow idempotent. Verwenden Sie die Stripe-Event-ID als Idempotenz-Schlüssel. Überprüfen Sie zu Beginn des Workflows die Webhook-Signatur und versuchen Sie, diese Event-ID in eine PostgreSQL-Tabelle mit einer Unique-Constraint einzufügen. Fahren Sie nur fort, wenn das Einfügen erfolgreich ist. Wenn die ID bereits vorhanden ist, geben Sie eine erfolgreiche Antwort zurück und stoppen Sie, ohne die Bestellung erneut zu erstellen.
Eine einfache Tabelle kann event_id als Primärschlüssel sowie status, received_at und completed_at enthalten. Verwenden Sie im Postgres-Node ein Insert mit ON CONFLICT DO NOTHING und geben Sie zurück, ob eine Zeile eingefügt wurde. Senden Sie dieses Ergebnis an einen IF-Node. Der True-Branch verarbeitet die Bestellung und der False-Branch beendet den Prozess. Die Datenbank-Constraint ist wichtig, da zwei Kopien so nah beieinander ankommen können, dass eine separate Lookup-Then-Insert-Prüfung beide durchlässt.
Markieren Sie den Datensatz als verarbeitet, wenn angefordert, und als abgeschlossen nur nach erfolgreichem Abschluss der Bestellung. Entscheiden Sie, wie fehlgeschlagene Datensätze wiederholt werden sollen, damit ein temporärer Fehler das Ereignis nicht dauerhaft unterdrückt. Geben Sie die Stripe-Event-ID auch an Downstream-Systeme als deren Idempotenz-Schlüssel weiter, sofern unterstützt. Deduplizieren Sie nicht nach Kunde, Betrag oder Zeitstempel, da separate legitime Zahlungen diese Werte gemeinsam nutzen können.
Erstelle einen Idempotency-Schlüssel aus einer stabilen Event-ID und speichere ihn, bevor die teuren Knoten ausgeführt werden. Falls derselbe Schlüssel erneut ankommt, kehre früh zurück und setze ein Ablaufdatum, das dem Zeitraum entspricht, in dem der Sender möglicherweise erneut versucht.