n8n error handling 完整指南:workflow 重試、告警通知與 dead letter queue 設計
n8n error handling 不能只靠 retry。本文整理三類失敗分流、exponential backoff 參數、Slack/PagerDuty 三級告警分層與 dead letter queue 完整設計,附 production 配置範例與 30 天落地檢核表。
n8n error handling 是讓 workflow 在第三方 API 卡關、限流或暫時斷線時不掉資料的整套機制,由三層組成:retry 策略(exponential backoff 加 idempotency key)、分層告警通知(Slack、Email、PagerDuty 依嚴重度分流)、dead letter queue(把 retry 用完仍失敗的事件落地,供之後 replay)。三層缺一就會在 production 補洞。
為什麼 n8n workflow 只設 retry 還不夠
很多人第一次處理 workflow 失敗,直覺就是把節點的 Retry On Fail 開起來,設個 Max Tries 3 次就收工。實際在 production 跑一段時間就會發現,這只解決一小塊問題。失敗有三類,混在同一條 retry 路徑會雪崩。
三類失敗模式分清楚
| 類別 | 例子 | 該怎麼做 |
|---|---|---|
| transient | Stripe 429、Cloudflare 524、OpenAI timeout | retry,配 exponential backoff |
| poison | payload JSON 解析失敗、必填欄位缺失 | 直接丟 DLQ,不該 retry |
| business | 訂單金額超上限、用戶不存在 | 回傳業務端處理,不算技術錯誤 |
把 poison 跟 transient 混在一起 retry,會把同一筆壞 payload 重複跑 3 次,每次都在 log 噴一樣的錯,看起來像 transient 其實永遠救不回。把 business 當 transient retry,會多打 3 倍 API 量、3 倍 LLM token,月底帳單炸開。
只設 retry 會踩的 3 個雷
- 雪崩:下游 API 5xx 時,每個 webhook 都進入 3 次 retry,下游本來只承受 100 QPS,retry 一開瞬間變 400 QPS,把對方打到永久掛掉。沒有指數退讓的 retry 是雪崩助推器。
- 重複扣款:retry 沒有 idempotency key,Stripe charge 失敗其實已扣款成功,retry 又扣一次。客戶看到帳單兩筆,客服當天炸鍋。這種事 2024 一份 n8n 用戶調查中有 23% 的金流團隊踩過。
- 靜默失敗:retry 3 次都失敗的事件,n8n 預設只在 execution log 留紀錄,沒人主動看就消失。等業務端來問「我這筆訂單怎麼沒進來」,已過 48 小時,event payload 在 execution log 早被 cleanup。
這三個雷直接告訴我們,production 級 error handling 一定要三層:retry 處理 transient、alert 確保有人看到、DLQ 確保 event 不會憑空消失。回看 n8n 工作流錯誤處理 7 種模式 列出的七種模式,本質上都是這三層的組合排列。
retry 策略怎麼設:exponential backoff + idempotency 兩條腿
retry 是三層的第一道防線,但 retry 設錯比不設更傷。production 級 retry 一定要兩條腿同時走:時間上做 exponential backoff,邏輯上掛 idempotency key。
n8n Retry On Fail 參數實戰
n8n 節點的 Settings 面板有兩個關鍵欄位:
- Max Tries:含第一次嘗試在內的總次數。production 建議 3 至 5,不要超過 5。
- Wait Between Tries (ms):每次間隔,注意 n8n 是固定間隔,不是原生 exponential backoff。
要做真正的 exponential backoff,得在 Error Trigger 那條路徑用 Wait 節點搭配 $itemIndex 動態計算等待時間。一份可上線的參數對照表:
| 嘗試次數 | 累積等待 | 適用場景 |
|---|---|---|
| 1 | 0s | 第一次直接打 |
| 2 | 1s | 處理偶發 502 |
| 3 | 4s | 抗 cloudflare cold start |
| 4 | 15s | 抗第三方限流恢復 |
| 5 | 60s | 抗短暫 region outage |
第 5 次還失敗就不該再 retry,進 DLQ。等待時間不該無上限,整個 retry 流程最長控制在 90 秒以內,否則 webhook 上游會自己 timeout。
idempotency key 怎麼設
idempotency 是 retry 不重複觸發副作用的唯一防線。三種常見情境:
- Stripe / Paypal / 金流 API:用 Stripe 提供的
Idempotency-KeyHTTP header,值帶 webhook event id。Stripe 24 小時內同一 key 第二次呼叫會回原本的 response,不會重扣。實作細節照 Stripe Idempotency 官方文件 即可。 - 自家 API:在請求 body 帶
client_request_id(UUID v4),後端建唯一索引擋重複。沒做這欄等於沒做 idempotency。 - Webhook 接收端:在 n8n 工作流入口先查
event_id是否已存在於 PostgreSQL 表,存在就 short-circuit 回 200,不再往下跑。這條最便宜,效果最好。
retry budget
retry 不是越多越好,要設總量上限。production 建議的 retry budget 公式:
單 workflow 每小時 retry 量 < (上游 QPS × 0.1)
10 QPS 的 webhook,每小時 retry 量不超過 1 QPS。超過就觸發 circuit breaker,暫停這條 workflow 5 分鐘,避免雪崩。n8n 沒內建 circuit breaker,要在 Error Workflow 用 Redis counter 自己做,每分鐘累積一個 key,超過閾值就回傳 503 給上游。
分層告警通知:把 noise 跟 incident 分開
retry 之後仍失敗的事件,下一步是讓對的人在對的時間看到。告警最容易踩的雷是「全部塞同一個 Slack channel」,跑兩週後沒人在看,alert fatigue 帶來的傷害比沒設 alert 還大。production 一定要分層。
三級告警分流表
| 等級 | 條件 | 通知管道 | 響應時限 |
|---|---|---|---|
| INFO | retry 1 次後成功 | 寫 log,不通知 | 不需要 |
| WARN | retry 3 次後成功 / 同類錯誤 5 分鐘內重複 | Slack channel #workflow-warn | 工作時間內看 |
| CRITICAL | retry 用盡仍失敗 / 金流相關 / DLQ 寫入 | PagerDuty + Slack #workflow-incident + 電話 | 15 分鐘內 |
n8n 沒內建分級邏輯,要在 Error Workflow 第一個節點用 Switch 判斷 $json.error.code 或 $json.workflow.name。金流類 workflow 名稱統一加 prod-payment- 前綴,Switch 直接認前綴丟 CRITICAL。
Error Workflow 的最小骨架
n8n 1.x 支援設 Error Workflow,在 main workflow Settings 選一個專門收錯誤的 workflow。最小骨架 5 個節點:
- Error Trigger — 接住所有失敗 event
- Set — 從
$json抽出 workflow name、error code、execution id、timestamp - Switch — 依嚴重度路由(依上表三級)
- De-dup(PostgreSQL)— 查 5 分鐘內同
(workflow_name, error_code)是否已通知過 - HTTP Request — 分別打 Slack / PagerDuty webhook
第 4 步的 de-dup 是 alert fatigue 的最大防線。沒做這層,同一個 API 掛 10 分鐘就會在 Slack 噴 100 則一模一樣的訊息。Error Workflow 本身也要寫 idempotency,免得它自己掛掉造成雙重通知,n8n 官方 Error Handling 文件 有完整範例。
alert fatigue 防範
實際跑半年的兩條反 alert fatigue 規則:
- 5 分鐘 de-dup:用 PostgreSQL 表
alert_dedup(workflow_name, error_code, last_notified_at),5 分鐘內同 key 不重複通知。第 6 分鐘觸發時,訊息加上「過去 5 分鐘累計 N 次」摘要。 - 夜間靜默:22:00–08:00 之間,只有 CRITICAL 等級會打 PagerDuty,WARN 一律延後到隔天早上 09:00 才推 Slack。需要在 Switch 節點額外判斷時間。金流相關 workflow 不適用此規則。
Slack / Discord webhook URL 千萬不要寫死在節點,要走 n8n credentials。這部分的治理做法整理在 n8n credentials 安全管理,alert 用的 webhook 算「中敏感」credential,建議 90 天輪替一次。
dead letter queue 設計:retry 用完還失敗的事件去哪裡
DLQ 是 error handling 的最後一層,也是最常被忽略的一層。沒有 DLQ,retry 用盡的 event 就只能靠 n8n execution log 找回來,過 7 天被 cleanup 就永遠消失。production 一定要有獨立 DLQ storage。
DLQ storage 三選一
| 方案 | 寫入難易 | replay 難易 | 月成本(1 萬筆/月) | 適合誰 |
|---|---|---|---|---|
| PostgreSQL table | 最簡單,n8n 原生節點即可 | 用 cron workflow 掃表 | 0 元(共用主 DB) | 5 至 30 人團隊,預設首選 |
| Redis Stream | 中等,需用 HTTP Request 打 Redis | XREADGROUP,需自家 dashboard | 約 200 元 (managed Redis) | 高頻寫入、要近即時 replay |
| S3 + manifest | 寫入便宜 | 手動 list bucket 較麻煩 | 約 30 元 (S3 + Glacier) | 超大量、retention 要 1 年以上 |
90% 的團隊 PostgreSQL table 就夠用,連 Redis 都不需要。資料量再大也是先把 PostgreSQL 撐到極限,再考慮分層儲存。AWS Builder’s Library 的 Avoiding Fallback in Distributed Systems 講得很清楚:把失敗事件落地比設計複雜 fallback 重要得多。
DLQ 寫入 schema
不論用哪種 storage,DLQ 紀錄至少要有 6 個欄位:
CREATE TABLE workflow_dlq (
id BIGSERIAL PRIMARY KEY,
event_id TEXT NOT NULL UNIQUE,
payload JSONB NOT NULL,
first_failed_at TIMESTAMPTZ NOT NULL,
last_error TEXT NOT NULL,
retry_count INT NOT NULL DEFAULT 0,
source_workflow TEXT NOT NULL,
replayed_at TIMESTAMPTZ,
status TEXT NOT NULL DEFAULT 'pending'
);
CREATE INDEX idx_dlq_status_first_failed ON workflow_dlq(status, first_failed_at);
event_id 加 UNIQUE 限制可同時當 idempotency 防線:同一 event 多次失敗只占一筆紀錄,每次失敗更新 retry_count 跟 last_error。status 三態 pending / replayed / discarded 對應 DLQ 的處置流程。
replay 機制
DLQ 不是垃圾桶,要有可預期的 replay 機制:
- 手動 replay:n8n 建一條獨立 workflow,用 Manual Trigger 接 PostgreSQL Read,給定
event_id後重新觸發原 workflow。適合 SRE 人工介入。 - cron 自動 replay:每小時跑一次,篩
status='pending' AND first_failed_at < NOW() - INTERVAL '1 hour'的 event。第二次仍失敗就標status='discarded'並推 CRITICAL alert。 - dashboard UI:對外用 n8nmarket templates 提供的 DLQ console 模板,給 PM 自己看哪些 event 卡住,不用每次都找工程師。
replay 要警惕兩件事:(1)poison message 不該 replay,要先在寫入 DLQ 時用 error_class 欄位標記類別,poison 一律 discarded;(2)replay 的 workflow 跟 main workflow 要走同一條 idempotency key,避免 replay 造成重複副作用。
一張藍圖把 retry + alert + DLQ 串起來
把三層拼成一張 production 配置藍圖,剛好對應 n8n 4 條 workflow。
標準 4 段配置
[main-workflow] ← 業務邏輯,每個節點開 Retry On Fail
│ 失敗
▼
[error-workflow] ← Error Trigger 接收
│
├─→ Switch ← 三級分流(INFO/WARN/CRITICAL)
│ │
│ ├─→ Slack/PagerDuty
│ └─→ De-dup table
│
└─→ HTTP/Postgres ← 寫入 workflow_dlq table
│
▼
[dlq-replay-workflow] ← cron 每小時掃 pending event
│
└─→ 重新觸發 main-workflow(帶原 event_id)
每段都是獨立 workflow,互不耦合。main-workflow 改業務邏輯不會動到 error 跟 DLQ。
webhook / scheduled / AI 三場景的差異
不同觸發類型 retry 設定要不同:
- webhook 觸發(Stripe、LINE、Slack):retry max 3 次,總長 < 25 秒(webhook 端通常 30 秒 timeout)。DLQ 寫入後立刻回 200 給上游。
- scheduled cron 觸發:retry max 5 次,可拉長到 5 分鐘總長。失敗直接寫 DLQ 等下一個 cron 週期 replay。
- AI 工作流(OpenAI、Claude、Gemini):retry max 2 次(避免 token 燒太兇),LLM 429 限流 backoff 拉長到 30 秒起跳。AI 場景 idempotency 用
prompt_hash當 key,相同 prompt 24 小時內回 cache 結果。自架 n8n 才有空間做這種訂製,這也是 自架 vs cloud 比較 中很多團隊最後選自架的原因之一。
第一個 30 天該做的 5 件事
剛接手一條沒做 error handling 的 production 線,30 天落地清單:
- D+0:所有節點打開 Retry On Fail,max 3,wait 2000ms。一行設定先擋住 50% 雪崩。
- D+7:建
error-workflow,接 main workflow Settings 的 Error Workflow 欄位。先只接 Slack#workflow-warn,不分級。 - D+14:建
workflow_dlqPostgreSQL table,error-workflow 末端寫入。同步在 main workflow 入口加 idempotency 檢查。 - D+21:補三級分流。CRITICAL 接 PagerDuty 或自己模擬(後述)。加 5 分鐘 de-dup table。
- D+30:建
dlq-replay-workflow,cron 每小時掃 pending event。第一週手動觀察 replay 成功率,調整 backoff。
每個檢查點都要量化:D+30 結束時看「過去 7 天 retry 自救率 / DLQ 進場率 / DLQ replay 成功率」三個指標,達 70% / < 1% / > 80% 算落地成功。
常見問題
retry 跟 idempotency 哪個先做?
idempotency 先做。沒有 idempotency 的 retry 是放大鏡,把一次失敗變成 N 次副作用。理想流程是先在 main workflow 入口加 event_id 查重 short-circuit,再開啟節點 Retry On Fail。沒做 idempotency 之前,retry 寧可關閉。
DLQ 應該存多久?什麼時候可以 purge?
預設 30 天保留,符合多數金流場景的 audit 需求。replay 成功的事件 7 天後 purge,status='discarded' 的 poison 保 90 天供 post-mortem。台灣個資法相關業務要看具體合約,沒明文就以 6 個月為上限。purge 一律用 cron workflow 做,不要手動 DELETE。
沒有 PagerDuty 預算怎麼辦?Slack 怎麼模擬 on-call?
PagerDuty 起步 $21/月/人,5 人團隊年費 $1260 不是每家都付得起。免費替代方案:(1)Slack 建 #workflow-incident-oncall channel,CRITICAL 訊息加 <!channel> 跟 on-call 工程師 @mention;(2)寫個簡單 n8n workflow,CRITICAL 發生時打 Twilio API 撥電話到當班手機,Twilio 每通 $0.013,比 PagerDuty 划算太多;(3)值班輪表用 Google Calendar 共享,n8n 用 Calendar API 查當下是誰。三招組合等於 80% PagerDuty 功能。
挑可上線的錯誤處理模板可以直接到 n8nmarket templates 看,挑含 Error Workflow + DLQ 範本的版本下載改一改,能省下 3 至 5 天從零搭建時間。先把 retry + Slack 通知接起來,再升 DLQ 跟 PagerDuty,是 production 級 error handling 落地最不會走偏的路徑。