Ich arbeite an einem Produktions-Workflow, bei dem eine externe API gelegentlich denselben Webhook erneut versucht, sodass n8n innerhalb weniger Sekunden doppelte Ereignisse empfangen kann. Der Workflow erstellt Datenbankdatensätze und löst nachgelagerte Aktionen aus, daher fühlt sich das einfache Überprüfen des Ausführungsverlaufs nicht zuverlässig an.
Ich erwäge, PostgreSQL mit einer eindeutigen Ereignis-ID und einem INSERT … ON CONFLICT DO NOTHING zu verwenden, bevor ich mit dem Workflow fortfahre.
INSERT INTO webhook_events (event_id, received_at)
VALUES ($1, NOW())
ON CONFLICT (event_id) DO NOTHING
RETURNING event_id;
ist dies ein gutes Muster, oder würdest du Deduplication anders handhaben?
Beschreibe das Problem/den Fehler/die Frage
Was ist die Fehlermeldung (falls vorhanden)?
Bitte teile deinen Workflow mit
(Wähle die Knoten auf deinem Canvas aus und verwende die Tastaturkürzel CMD+C/STRG+C und CMD+V/STRG+V zum Kopieren und Einfügen des Workflows.)
Gib die Ausgabe aus, die der letzte Knoten zurückgibt
Hallo @Sophia_Bennett Ja, ich würde die Datenbank als Quelle der Wahrheit verwenden, anstatt mich auf den n8n-Ausführungsverlauf zu verlassen.
Eine eindeutige event_id plus INSERT … ON CONFLICT DO NOTHING gibt dir eine atomare Deduplizierungsprüfung, auch wenn mehrere Worker das gleiche Event fast zur gleichen Zeit erhalten.
INSERT INTO webhook_events (event_id, received_at)
VALUES ($1, NOW())
ON CONFLICT (event_id) DO NOTHING
RETURNING event_id;
Wenn keine Zeile zurückgegeben wird, behandle sie als Duplikat und stoppe den Workflow. Ich würde auch einen Index/eine Unique-Constraint auf event_id hinzufügen und den Deduplizierungsdatensatz so lange behalten, wie der Provider Events erneut versuchen kann.
Für kritischere Workflows würde ich auch den Status (verarbeitung, abgeschlossen, fehlgeschlagen) verfolgen, damit Wiederholungen sicher fortgesetzt werden können, ohne Duplikate bei Nebenwirkungen zu erzeugen.
Ja, das ist das richtige Muster. ON CONFLICT DO NOTHING ist atomar, sodass zwei gleichzeitige Lieferungen nicht beide durchkommen können. Um es produktionssicher zu machen:
Gate: Füge nach dem Insert einen If-Knoten hinzu: {{ $json.event_id }} ist nicht leer. Duplikate geben keine Zeile zurück und stoppen dort.
Fehler: Wenn der Workflow nach dem Insert fehlschlägt, wird der Wiederholungsversuch als Duplikat verworfen und das Event geht verloren. Füge eine status-Spalte hinzu, setze sie am Ende auf done und lösche oder markiere die Zeile bei einem Fehler als failed, damit der Wiederholungsversuch durchgehen kann.
Antworte sofort im Webhook-Knoten. Langsame Antworten sind das, was die meisten Wiederholungsversuche auslöst.
Bereinige Zeilen, die älter als ein paar Tage sind, mit einem Schedule-Workflow.
Hi @Sophia_Bennett, ja, mit einer Non-Null-Unique event_id ist das ein gutes atomares Gate. Aber lösch die Event-Zeile nicht bei jedem Fehler: Eine nachgelagerte API kann die Aktion abschließen, bevor n8n abbricht, also könnte ein erneuter Versuch sie wiederholen.
Wenn deine Business-Records in derselben PostgreSQL-Datenbank sind, schreibe die Event-ID, Business-Writes und eine Outbox-Zeile für nachgelagerte Arbeit zusammen. Eine gespeicherte Prozedur, die über Postgres Execute Query aufgerufen wird, kann das tun und die Writes nur anwenden, wenn der Event-Insert erfolgreich ist. Gib 200 über Respond to Webhook nach diesem Commit zurück.
Verarbeite die Outbox separat und verwende einen stabilen Idempotency-Key pro Event/Aktion, wenn die empfangende API das unterstützt. Sonst prüfe unsichere Ergebnisse vor erneutem Versuch. Behalte Event-IDs für das Retry/Replay-Fenster des Providers, nicht für einen willkürlich festgelegten Zeitraum.
Hallo @Sophia_Bennett Ja, das ist ein starkes Muster für die Produktion. Ich würde PostgreSQL als Quelle der Wahrheit für die Deduplizierung verwenden, anstatt mich auf die n8n-Ausführungshistorie zu verlassen.
Der wichtige Teil ist die Unique Constraint:
CREATE UNIQUE INDEX ux_webhook_events_event_id
ON webhook_events (event_id);
Dann wird dein Insert atomar:
INSERT INTO webhook_events (event_id, received_at)
VALUES ($1, NOW())
ON CONFLICT (event_id) DO NOTHING
RETURNING event_id;
Wenn RETURNING dir die event_id gibt, hat diese Ausführung das Event erfolgreich beansprucht und kann fortfahren.
Wenn es nichts zurückgibt, hat eine andere Ausführung dieses Event bereits verarbeitet oder beansprucht, sodass der Workflow stoppen sollte, bevor Datensätze erstellt oder nachgelagerte Aktionen ausgelöst werden.