工作流程在 Worker 重啟後隨機重新處理舊佇列工作

嗨各位,
我在用佇列模式執行 n8n,搭配多個 worker,重新啟動 worker 或部署後發現了一個奇怪的問題。
我的設置:Webhook → Queue → Worker → Process → Database
有時候 worker 重新啟動後:
舊的工作會被重新處理
一些工作看起來「卡住」了,稍後會意外重試
少數執行會造成重複的資料庫寫入/API 呼叫
我已經使用重試和基本的錯誤處理,但我認為問題與工作如何被確認或在 worker 崩潰後恢復有關。
範例處理邏輯:if ($json.status !== “processed”) {
// continue processing
}
我想了解:
• n8n 佇列模式如何在重新啟動後處理未完成的工作
• 工作是否會自動重新進入佇列
• 在崩潰後如何最好地讓工作流程安全地防止重複執行
針對在生產環境中使用佇列模式的人:
• 崩潰恢復和冪等性處理的建議模式是什麼?

描述問題/錯誤/問題

錯誤訊息是什麼(如果有的話)?

請分享你的工作流程

(在畫布上選擇節點並使用鍵盤快捷鍵 CMD+C/CTRL+C 和 CMD+V/CTRL+V 來複製和貼上工作流程。)

分享最後一個節點返回的輸出

關於你的 n8n 設置的資訊

  • n8n 版本:
  • 資料庫(預設:SQLite):
  • n8n EXECUTIONS_PROCESS 設定(預設:own、main):
  • 執行 n8n 的方式(Docker、npm、n8n cloud、桌面應用):
  • 作業系統:

@Decoure_Ryan 你看到的通常是佇列模式中的正常行為。如果 worker 在工作完全完成/確認之前崩潰或重啟,佇列可以將該工作標記為未完成,並稍後重新處理它。這就是你看到舊工作再次執行的原因。

嘗試假設工作可以運行多次,並使處理冪等。

例如,在處理前:if ($json.status === “processed”) {
return ;
}

並使用資料庫層級的保護,例如:ON CONFLICT DO NOTHING

或唯一鍵來防止重複插入。

你可以應用的常見生產方式
佇列處理重試/復原
資料庫處理去重/冪等性
Workers 保持無狀態

歡迎 @Decoure_Ryan 加入我們的社群!我是 Jay,我是 n8n 認證創作者。

補充 Niffzy 說的話 - 根本原因是 Bull 的「停滯任務」恢復機制。當一個 worker 重啟而沒有正確完成一個任務時,Bull 會在 QUEUE_BULL_STALLED_INTERVAL 毫秒(預設 30000ms)之後將該任務標記為停滯,並將其重新入隊。你可以使用 QUEUE_BULL_MAX_STALLED_COUNT=1 來調整停滯任務最多重試次數,並使用 QUEUE_BULL_STALLED_INTERVAL 來控制檢測時間窗口。為了在 n8n 層級確保冪等性,在工作流程的最開始使用 $getWorkflowStaticData 或執行資料庫狀態檢查,如果 execution_id 已經被處理過就直接返回。在資料庫的 execution_id 設定唯一約束是最可靠的防護措施。

歡迎來到 n8n 社群 @Decoure_Ryan

Redis 充當 broker,workers 執行 jobs,但我不會假設 exactly-once 的保證;在崩潰/重新啟動後,請視為 at-least-once,檢查 N8N_GRACEFUL_SHUTDOWN_TIMEOUT 並設計工作流程來處理重新處理。

(我不是在大喊是為了更加強調 :blush:
一律使用唯一金鑰
99% 的問題都可以用這個解決

感謝 @Niffzy @nguyenthieutoan 的回覆

感謝 @syed_noor 的精彩分析。我想補充一點:BullMQ 還有一個 lockDuration 設定(預設 30 秒)— 如果你的工作流程耗時超過這個時間,鎖定就會過期,工作會被標記為停滯,即使仍在執行中。你可以透過上述的 QUEUE_BULL_STALLED_INTERVAL 提高它,但也要確保在你的 BullMQ 設定中適當設定 lockDuration

另外值得注意的是 — PostgreSQL 冪等性金鑰方法是我在生產環境中見過最可靠的模式。將它與 n8n 的「停止並報錯」(Stop and Error) 節點結合,在 INSERT 檢查後使用,可以乾淨地退出重複執行,而不會污染你的錯誤日誌。

感謝你 brudda,我也遇到同樣的 problemo,這個幫助了我很多,祝你有美好的一天!!!

很好的補充,感謝你特別指出 lockDuration 的區別。
QUEUE_BULL_STALLED_INTERVAL 控制檢查器的執行頻率,但 lockDuration 控制工作在被認為已停滯之前可以保持活躍多長時間。兩者都需要超過你最長的工作流執行時間。

Stop 和 Error 節點的提示也很有用。我在冪等性 INSERT 之後使用它,並將訊息設定為 job_id——這樣當你在 n8n 中檢視執行紀錄時,可以立即看到哪些是合法的重複項,哪些是真正的失敗。這樣可以保持執行列表的清潔,而不是顯示誤報錯誤。

對於實施這個模式的任何人,我在這裡撰寫了更詳細的說明,涵蓋全部六個生產就緒性維度(冪等性只是其中之一):

Stop 和 Error 訊息中的 job_id 是一個不錯的設計 - 當你掃描執行時,可以大大加快分類速度。在這個模式基礎上還有一個值得加入的東西:在冪等性檢查節點上設置 continueOnFail,並將「已處理」路徑路由到一個清晰命名的 No-op 節點(例如「DUPLICATE - skipped」),而不是完全依賴錯誤路徑。這樣可以保持執行圖的可讀性,並一目了然地將預期的跳過與實際失敗區分開來。