N8n wird mit der Zeit langsamer (40k+ Ausführungen/Monat)

Das Problem/den Fehler/die Frage beschreiben

Wir betreiben eine selbst gehostete n8n-Instanz auf Railway und haben mit zunehmenden Leistungsproblemen zu kämpfen, da unsere Nutzung gewachsen ist.
Wir verarbeiten derzeit mehr als 40.000 Workflow-Ausführungen pro Monat.
Das Hauptproblem ist, dass Workflows, die normalerweise etwa 1 Sekunde dauern sollten, jetzt häufig 3–4 Sekunden brauchen, um zu Ende zu kommen, obwohl sich die Workflow-Logik selbst nicht geändert hat.
Wir sehen auch zufällig entstehende Ausführungswarteschlangen. Das sollte nicht passieren, basierend auf unserer aktuellen Konfiguration, da wir absichtlich keine Concurrency-Limits konfiguriert haben.
Kürzlich haben wir auch begonnen, diesen Fehler zu sehen:
Diese Ausführung konnte zu viele Male nicht verarbeitet werden und wird nicht mehr wiederholt. Um diese Ausführung abzuschließen, unterteilen Sie bitte Ihren Workflow oder skalieren Sie Ihre Worker hoch oder passen Sie Ihre Worker-Einstellungen an.

Wir wissen ehrlich gesagt nicht, was wir noch versuchen sollen. Die Railway-Metriken für unsere Worker, primäre Instanz und PostgreSQL sehen alle gesund aus, ohne offensichtliche Ressourcenengpässe. Hat jemand etwas Ähnliches erlebt oder hat Ideen, was wir als Nächstes untersuchen sollten?

Wie lautet die Fehlermeldung (falls vorhanden)?

Bitte teilen Sie Ihren Workflow

(Wählen Sie die Knoten auf Ihrer Canvas aus und verwenden Sie die Tastaturkürzel CMD+C/STRG+C und CMD+V/STRG+V zum Kopieren und Einfügen des Workflows.)

Geben Sie die vom letzten Knoten zurückgegebene Ausgabe an

Informationen zu Ihrem n8n-Setup

  • n8n-Version: 2.28.4
  • Datenbank: PostgreSQL
  • n8n EXECUTIONS_PROCESS-Einstellung (Standard: own, main):
  • n8n wird ausgeführt über (Docker, npm, n8n cloud, Desktop-App): railway
  • Betriebssystem: windows 11

Hallo @jptg

Basierend auf den Symptomen und der Fehlermeldung, die du siehst, leidet deine n8n-Instanz wahrscheinlich unter Process Overhead und Database Bloat, was häufig vorkommt, wenn selbst gehostete Instanzen sich 40.000+ Ausführungen pro Monat nähern.

Der Fehler *„This execution failed to be processed too many times

Hallo, danke für die ausführliche Antwort!

Wir laufen bereits im Queue Mode, und wir haben jetzt fast alle deine Vorschläge umgesetzt.

  • Wir hatten Queue Mode bereits konfiguriert.
  • Wir haben die Ausführungs-Bereinigung aktiviert (EXECUTIONS_DATA_PRUNE, EXECUTIONS_DATA_MAX_AGE, usw.).
  • Wir haben auch die Worker-Lock-Dauer erhöht.

Den einzigen Vorschlag, den wir nicht umgesetzt haben, war EXECUTIONS_PROCESS=main, denn nach unserem Verständnis ist diese Einstellung in neueren n8n-Versionen veraltet und nicht anwendbar, wenn Queue Mode verwendet wird.

Momentum hatten wir noch keine Gelegenheit zu überprüfen, ob diese Änderungen die Situation verbessert haben, da die Leistungsverschlechterung intermittierend auftritt. Wir warten auf den nächsten Incident, um zu sehen, ob das Problem wieder auftritt.

Ich werde mehrere Instanzen von n8n ausführen, um das ganz zu vermeiden.

In meiner letzten Position hatte ich eine Instanz für jede Abteilung des Unternehmens

Service
Operations
Marketing
HR
Development (mein Workflow-Friedhof)

was mich auch dazu trieb, eine Management-Plattform dafür zu erstellen lol

Du hast tatsächlich die richtigen Dinge getan — Queue-Modus, Pruning, der Lock Bump — und du hast recht, dass EXECUTIONS_PROCESS veraltet ist (Own-Process-Modus wurde entfernt; auf modernem n8n ist alles Main oder Queue/Worker, also war das für dich ein No-Op). Das Problem ist, dass du vier Variablen auf einmal ohne Baseline geändert hast, also selbst wenn es sich verbessert hat, kannst du nicht sagen, welcher Parameter es war. Bevor du weitere änderst, misst du — hier ist, wie du erkennst, welche der drei üblichen Engpässe du wirklich hast: DB I/O, Worker-Contention oder ein einzelner leaking Workflow.

Pruning zu aktivieren reclaims nicht das, was bereits da ist. EXECUTIONS_DATA_PRUNE verhindert nur, dass neue Reihen in Zukunft über deinen Threshold hinauswachsen — es schrumpft keine Tabelle, die bereits aufgebläht ist. In Postgres werden gelöschte Reihen zu Dead Tuples, und die On-Disk-Größe von execution_data (die Payload-Tabelle — die große, nicht execution_entity) plus deren Indizes bleibt groß, bis es vacuumt wird, und Autovacuum kann oft nicht mithalten mit einer Tabelle, die bereits riesig geworden ist. Also „wir haben Pruning aktiviert und nichts hat sich geändert

Wenn er KI-Antworten wollte, hätte er Claude, ChatGPT usw. verwendet.

Eine Ergänzung zu einem Punkt, den ich beim ersten Mal hätte einbeziehen sollen, weil er der Grund dafür ist, dass der Pruning-Rat so aussieht, als hätte er nicht funktioniert.

Wenn du die beiden pg_stat-Abfragen ausgeführt hast und execution_data immer noch riesig ist, überprüfe, ob die Zeilen tatsächlich weg sind oder nur als gelöscht markiert sind, bevor du schlussfolgerst, dass Pruning kaputt ist. n8n’s Pruning führt den Delete in Stufen durch, also gibt es ein Zeitfenster, in dem Executions zum Entfernen gekennzeichnet sind, aber die Payload-Zeilen immer noch physisch vorhanden sind. Bei einer ausgelasteten Instanz, die neu gestartet wurde, kann die gekennzeichnete Rückstau auf unbestimmte Zeit dort sitzen bleiben. Der Vergleich der Zeilenanzahl in execution_entity mit dem, was die UI dir als vorhandene Executions zeigt, reicht normalerweise aus, um zu sehen, in welcher Situation du dich befindest, und es ändert die Lösung grundlegend: Wenn die Zeilen bereits weg sind, hast du Dead-Tuple-Bloat und brauchst ein Repack. Wenn sie noch da sind, hilft kein Vakuumieren, bis sie tatsächlich entfernt sind.

Die zweite Hälfte ist speziell auf Railway relevant. pg_repack baut die Tabelle neben dem Original auf, bevor es tauscht, daher benötigt es freien Speicher, der ungefähr der Größe der Tabelle und ihrer Indizes entspricht. Wenn execution_data das meiste Volumen ausmacht, wird das Repack eine Weile laufen und dann auf Speicher fehlschlagen, und du wirst in einer schlechteren Position sein als am Anfang. Überprüfe zuerst den freien Speicher gegen pg_total_relation_size. Wenn der Puffer nicht vorhanden ist, ist die günstigere Route, die Zeilenanzahl zuerst stark nach unten zu bringen, in Batches, damit du keine eine riesige Transaktion hältst, und erst dann den Speicher freizugeben.

Es ist der Mühe wert, klar zu sagen: Wenn die beiden Abfragen auf den Worker statt auf die Datenbank hinweisen, ist nichts von all dem oben dein Problem und ich würde es ignorieren.