0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

n8nのリトライ設定が失敗を5倍に増やした — retryOnFailとエラーワークフローの正しい切り分け

0
Posted at

n8nで夜間バッチを運用していて、「失敗が怖いから」と全ノードにリトライ設定を付けたら、失敗通知が5倍になりました。原因は、リトライで直る失敗(一時的)と、いくらリトライしても直らない失敗(恒久的)を分類しないまま、同じ設定を5つのノード全部に敷き詰めたことでした。この記事では、失敗を3分類してretryOnFail・エラーワークフロー・冪等キーの3つの対策を切り替える設計を、インポートして動くワークフローJSON付きで書きます。

何が起きたか: リトライを付けたら失敗が5倍になった

23:40起動の夜間バッチ(外部API取得1本・LLMノード3本・Notion書き込み1本、計5ノード)で実測したタイムラインです。

時刻 起きたこと
23:40 バッチ開始
23:47 外部APIが429(レート制限)を返す。retryOnFail=ON・maxTries=5・待ち0秒で即時5連打し、5回とも429
23:52 LLMノードもレート制限に当たり、同設定でその日のquotaを5回分消費
0:05 Notion書き込みが409(競合)を返す。ここも5回リトライして、全部失敗
0:12 通知に「失敗」が5回×3ノードで計15通

この夜の429は「1分待てば消える」一時的なものでした。待ち0秒で上限5回の即時再試行は、成功確率を一切上げずに、相手側のレート制限カウンターと自分のAPI quotaを回すだけの自傷でした。リトライの数だけ失敗が増えている、という妙な状態はこの仕組みで起きます。

失敗は3種類。対策は1対1で切り替える

分類し直した結果が次の表です。n8nで起きる失敗は3種類に整理でき、対策が1対1に対応します。

失敗の種類 具体例 正しい対策
一時的(待てば直る) 429・503・ネットワークタイムアウト retryOnFail=ON・maxTries=3・waitBetweenTries=5000
恒久的(何回やっても直らない) 401権限不足・404のURL・バリデーションエラー リトライは付けない。エラーワークフローへ逃して通知
データ依存(やり直すと二重登録) 部分完了したあとの書き込み 冪等キーを外部側に持たせ、同じ処理は1回だけ成功させる

ポイントは「リトライで直るのは1行目だけ」という事実です。2行目にリトライを付けると失敗の繰り返しが増え、3行目にリトライを付けると二重登録が増えます。私はこの3種類を区別せずに全部のノードへ付けていて、まさにタイトル通りの結果になりました。

直し方1: 一時的失敗にはretryOnFail(上限3回・5秒待ち)

一時的失敗を想定するノードには、ノードのSettingsタブで次の値を入れます。

  • Retry On Fail: ON
  • Max Tries: 3
  • Wait Between Tries: 5000(ミリ秒)

n8nのリトライは固定間隔で、指数バックオフは標準機能にはありません。それでも「5秒×上限3回」は、1分で回復する種類のレート制限に対して十分実用的でした。もっと長い待ちを組みたくなったらWaitノードで自作するのではなく、まず相手側APIの制限設計(1時間あたりの枠など)を確認する方が費用対効果が高い、というのが実測からの学びです。

直し方2: 恒久的失敗はエラーワークフローへ逃す

設定手順は3つです。

  1. 新規ワークフロー(名前例: error handler)を作り、失敗通知ノード(Slackやメール)を1つ置く
  2. 本体ワークフローのSettings → Error Workflowで、作ったerror handlerを指定する
  3. ノード単位で拾うときは、ノードのSettings → On Error → Continue(using error output)を選ぶ。ノードに赤いエラー出力が増えるので、そこから分岐する

error handlerが受け取るデータは次の形です($json直下)。

{
  "workflow": { "id": "123", "name": "夜間バッチ本体" },
  "execution": {
    "id": "4567",
    "url": "https://n8n.example.com/execution/4567",
    "lastNodeExecuted": "外部API",
    "error": { "message": "Request failed with status code 401" }
  }
}

重要なのは lastNodeExecuted と execution.url です。通知にURLを入れておけば、失敗の翌朝にログを開かず現場へ直行できます。

直し方3: 再実行で二重登録が起きる書き込みには冪等キー

Notionやスプレッドシートへの書き込みノードは、リトライや再実行で同じ行が2回入ります(静かに、通知なしで)。同じ処理であれば同じ値になるキーを作り、外部側のユニーク制約に渡すのが一番安い設計でした。

// Codeノード(Run Once for All Items)
const key = $now.toFormat('yyyy-MM-dd') + '-' + String($execution.id);
return [{ json: { idempotencyKey: key } }];

このキーをNotionのユニークなテキストプロパティ(同一キーなら上書きする運用)や社内DBのユニーク制約に渡せば、リトライでも再実行でも1行しか入りません。

3つ全部を入れたワークフローJSON(インポートしてそのまま動く)

{
  "name": "夜間バッチ_リトライ設計デモ",
  "settings": { "executionOrder": "v1" },
  "nodes": [
    {
      "parameters": {
        "rule": { "interval": [ { "field": "cronExpression", "expression": "40 23 * * *" } ] }
      },
      "name": "23:40起動",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [200, 300]
    },
    {
      "parameters": {
        "jsCode": "const key = $now.toFormat('yyyy-MM-dd') + '-' + String($execution.id);\nreturn [{ json: { idempotencyKey: key } }];"
      },
      "name": "冪等キー生成",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [420, 300]
    },
    {
      "parameters": { "method": "GET", "url": "https://httpstat.us/429", "options": {} },
      "name": "外部API(429が必ず返る)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [640, 300],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000,
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {},
      "name": "成功側: ここから書き込み(冪等キーを必ず渡す)",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [880, 220]
    },
    {
      "parameters": {
        "jsCode": "const msg = (($json.error || {}).message) || $json.message || '';\nlet cat = 'transient';\nif (/429|503|timeout|timed out/i.test(msg)) cat = 'transient';\nelse if (/401|403|404/i.test(msg)) cat = 'permanent';\nelse if (msg) cat = 'data';\nreturn [{ json: { category: cat, message: msg, workflow: $workflow.name } }];"
      },
      "name": "失敗を3分類",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [880, 400]
    },
    {
      "parameters": {},
      "name": "通知をここに接続(Slack / メール)",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [1100, 400]
    }
  ],
  "connections": {
    "23:40起動": { "main": [[{ "node": "冪等キー生成", "type": "main", "index": 0 }]] },
    "冪等キー生成": { "main": [[{ "node": "外部API(429が必ず返る)", "type": "main", "index": 0 }]] },
    "外部API(429が必ず返る)": {
      "main": [
        [ { "node": "成功側: ここから書き込み(冪等キーを必ず渡す)", "type": "main", "index": 0 } ],
        [ { "node": "失敗を3分類", "type": "main", "index": 0 } ]
      ]
    },
    "失敗を3分類": { "main": [[{ "node": "通知をここに接続(Slack / メール)", "type": "main", "index": 0 }]] }
  }
}

インポート手順: n8nのワークフロー一覧 → 「Import from Clipboard」でJSONを貼り付ける。「外部API(429が必ず返る)」は httpstat.us を使い、429が必ず返るようになっています。実行すると「5秒×3回のリトライ → エラー出力 → 分類 → 通知ノード」の流れがその場で見られます。成功側の流れだけ見たいときはURLの /429 を /200 に変えてください。恒久的失敗を試すときは /404 に変えます(404はリトライ不要の分類ですが、retryOnFailを付けたままにしているとここでも3回走ります。外すのがこの記事の趣旨です)。

失敗パターン: LLMノードにリトライを付けたままにしていた

私はLLMノード3本にもretryOnFail=ON・maxTries=5を付けたままにしていました。LLM側の429は「1日あたりのquota」で、回復が翌日になる種類の制限です。リトライ5回はquotaの無駄撃ちとして確定し、翌朝も同じ場所で全部失敗しました。LLMノードのリトライは外し、エラーワークフローで「夜間の失敗は朝一に1通通知」へ変えたところ、quotaは回復し、通知は15通から1通になりました。LLMのレート制限はネットワークの一時的失敗ではなく、日次quotaという種類の制限として扱うのが正解でした。

まとめ

  • retryOnFailは「一時的失敗(429・503・タイムアウト)」のノードだけに付ける。値はMax Tries=3・Wait Between Tries=5000から始める
  • 恒久的失敗(401・404・バリデーション)はエラーワークフローへ逃す。通知にexecution URLを入れ、翌朝ログを開かず現場へ行ける形にする
  • 書き込みノードは冪等キー。「日付+実行ID」でキーを作り、外部のユニーク制約に渡せば二重登録が消える
  • 次のアクション: 今日動いているワークフローを1本開き、全ノードのSettingsでretryOnFailの付け場所を確認する。LLMノードと書き込みノードに付いていたら外すのが最初の一手です。

🎁 読者特典を受け取る(無料・メール登録)

参考書籍: n8n × AI自動化実践入門 — ノーコードで作るAIワークフロー(Kindle・Kindle Unlimited読み放題対象)(葉山悠希 著)

著者: 葉山悠希 — 書籍シリーズは Zenn / Amazon で公開中

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?