Hallo zusammen,
Ich betreibe n8n im Queue-Modus mit mehreren Workern, und ich sehe ein seltsames Problem nach dem Neustart von Workern oder Deployments.
Mein Setup: Webhook → Queue → Worker → Process → Database
Manchmal nach einem Worker-Neustart:
Alte Jobs werden erneut verarbeitet
Einige Jobs erscheinen “steckengeblieben” und werden später unerwartet erneut versucht
Einige Ausführungen erstellen doppelte DB-Schreibvorgänge/API-Aufrufe
Ich nutze bereits Wiederholungen und grundlegendes Fehlerbehandlung, aber ich glaube, das Problem hängt damit zusammen, wie Jobs bestätigt oder nach Worker-Crashes wiederhergestellt werden.
Beispiel-Verarbeitungslogik:
if ($json.status !== “processed”) {
// Verarbeitung fortsetzen
}
Ich versuche zu verstehen:
• Wie n8n Queue-Modus unvollendete Jobs nach dem Neustart handhabt
• Ob Jobs automatisch erneut in die Warteschlange eingereiht werden
• Beste Möglichkeit, Workflows vor doppelter Ausführung nach Crashes zu schützen
Für Leute, die Queue-Modus in der Produktion nutzen:
• Welches ist das empfohlene Muster für Crash-Wiederherstellung und idempotente Verarbeitung?
Das Problem/den Fehler/die Frage beschreiben
Welche Fehlermeldung gibt es (falls vorhanden)?
Bitte teilen Sie deinen Workflow
(Wähle die Knoten auf deiner Canvas aus und nutze die Tastaturkürzel CMD+C/STRG+C und CMD+V/STRG+V zum Kopieren und Einfügen des Workflows.)
Hallo @Decoure_Ryan Das, was du siehst, ist normalerweise ein erwartetes Verhalten im Queue-Modus. Wenn ein Worker abstürzt oder neu startet, bevor ein Job vollständig abgeschlossen/bestätigt wird, kann die Queue diesen Job als unvollständig markieren und ihn später erneut verarbeiten. Deshalb siehst du alte Jobs erneut ausgeführt.
Versuche anzunehmen, dass Jobs mehr als einmal ausgeführt werden können, und mache die Verarbeitung idempotent.
Zum Beispiel, vor der Verarbeitung:
if ($json.status === “processed”) {
return ;
}
Und verwende Datenbankschutz auf Datenbankebene wie:
ON CONFLICT DO NOTHING
oder Unique Keys, um doppelte Inserts zu verhindern.
Häufige produktive Wege, die du anwenden kannst
Queue handhabt Wiederholungen/Wiederherstellung
Datenbank handhabt Deduplizierung/Idempotenz
Worker bleiben zustandslos
Willkommen @Decoure_Ryan in unserer Community! Ich bin Jay und bin ein verifizierter n8n Creator.
Zum Ergänzen dessen, was Niffzy gesagt hat - die Grundursache ist Bulls “stalled job” Wiederherstellungsmechanismus. Wenn ein Worker neu startet, ohne einen Job ordnungsgemäß zu beenden, markiert Bull diesen Job nach QUEUE_BULL_STALLED_INTERVAL Millisekunden (Standard 30000ms) als stalled und stellt ihn wieder in die Warteschlange. Du kannst dies mit QUEUE_BULL_MAX_STALLED_COUNT=1 anpassen, um zu begrenzen, wie oft ein stalled Job wiederholt wird, und QUEUE_BULL_STALLED_INTERVAL, um das Erkennungsfenster zu steuern. Für Idempotenz auf n8n-Ebene nutze $getWorkflowStaticData oder eine DB-Statusprüfung ganz am Anfang des Workflows, um den Prozess zu unterbrechen, falls die execution_id bereits verarbeitet wurde. Das Setzen einer Unique Constraint auf execution_id in deiner Datenbank ist die zuverlässigste Sicherungsmaßnahme.
Redis fungiert als Broker und die Worker führen die Jobs aus, aber ich würde keine Garantie für exactly-once übernehmen; nach Crash/Restart solltest du von at-least-once ausgehen, überprüfe N8N_GRACEFUL_SHUTDOWN_TIMEOUT und gestalte den Workflow so, dass er mit Neuverarbeitung umgehen kann.
(ich schreie nicht, sondern möchte nur mehr Nachdruck verleihen )
VERWENDE IMMER EINEN EINDEUTIGEN SCHLÜSSEL
99% der Probleme könnten damit gelöst werden
Großartige Zusammenfassung von @syed_noor. Eine Sache, die ich noch hinzufügen würde: BullMQ hat auch eine lockDuration-Einstellung (Standard 30s) — wenn dein Workflow länger dauert, läuft die Sperre ab und der Job wird als stalled gekennzeichnet, obwohl er noch läuft. Du kannst ihn über QUEUE_BULL_STALLED_INTERVAL erhöhen, wie erwähnt, aber stelle auch sicher, dass lockDuration in deiner BullMQ-Konfiguration angemessen eingestellt ist.
Auch erwähnenswert — der Postgres-Idempotenzschlüssel-Ansatz ist das zuverlässigste Pattern, das ich in der Produktion gesehen habe. Kombiniere ihn mit n8n’s “Stop and Error”-Node nach der INSERT-Überprüfung, um doppelte Ausführungen sauber zu beenden, ohne deine Error-Logs zu verschmutzen.
Gute Ergänzung zur lockDuration-Unterscheidung — ich hätte das separat ansprechen sollen. QUEUE_BULL_STALLED_INTERVAL steuert, wie oft der Checker läuft, aber lockDuration steuert, wie lange ein Job aktiv sein kann, bevor er als stagnierten (stalled) betrachtet wird. Beide müssen länger sein als deine längste Workflow-Ausführungszeit.
Der Tipp mit Stop und Error Node ist auch solide. Ich nutze das nach dem Idempotenz-INSERT mit der Nachricht auf die job_id gesetzt — auf diese Weise kannst du bei der Überprüfung von Ausführungen in n8n sofort sehen, welche davon legitime Duplikate waren und welche echte Fehler. Das hält die Ausführungsliste sauber, statt falsch-positive Fehler anzuzeigen.
Für alle, die dieses Muster implementieren, habe ich hier eine ausführlichere Übersicht über alle sechs Produktionsreife-Dimensionen geschrieben (Idempotenz ist nur eine davon):
Die job_id in der Stop- und Error-Nachricht ist ein raffinierter Kniff – macht die Triage deutlich schneller, wenn du Ausführungen durchsuchst. Noch eine Sache, die es wert ist, zu diesem Muster hinzuzufügen: Setze continueOnFail auf dem Idempotenzprüfungs-Node und leite den Pfad „bereits verarbeitet