第 26 期:永不崩溃 — 错误处理、重试与告警体系

⏱ 预计阅读 9 分钟 更新于 2026/4/9

生产环境的残酷现实

开发时一切正常的工作流,上线后会遇到:API 超时、限速、凭证过期、数据格式异常、第三方服务宕机...

graph TB
    subgraph "生产环境错误的三层防线"
        L1["🛡️ 第一层: 节点级
单个节点的重试与降级"] L2["🛡️ 第二层: 工作流级
Error Trigger 全局捕获"] L3["🛡️ 第三层: 系统级
多渠道告警 + 自动恢复"] end L1 --> L2 --> L3 style L1 fill:#22c55e,stroke:#16a34a,color:#fff style L2 fill:#f59e0b,stroke:#d97706,color:#fff style L3 fill:#ef4444,stroke:#dc2626,color:#fff

1. 节点级错误处理

graph TB
    Node[任意节点] --> Error{执行出错?}
    Error -->|"成功"| Next[正常继续]
    Error -->|"失败"| Strategy{错误处理策略}
    
    Strategy --> S1["🔄 Retry
重试 N 次后继续"] Strategy --> S2["⏭️ Continue
跳过此节点继续"] Strategy --> S3["🛑 Stop
停止整个工作流"] Strategy --> S4["🔀 Output Error
将错误作为输出传递"] style S4 fill:#22c55e,stroke:#16a34a,color:#fff
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 节点错误处理设置 (Settings → On Error)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// 策略 1: Retry on Fail
// - Max Retries: 3                   // 最多重试 3 次
// - Wait Between Retries: 2000ms     // 重试间隔 2 秒
// 适用: API 瞬时超时、网络抖动

// 策略 2: Continue on Error (最推荐)
// - 节点失败后,将错误信息作为 Item 传递给下游
// - 下游可以用 If 节点判断是否有错误
// 适用: 批量处理中个别 Item 失败不应影响整体

// 策略 3: Stop Workflow
// - 默认行为,任何节点失败立即终止
// 适用: 关键路径节点(如支付确认)

// 策略 4: Output Error Data
// 节点失败时输出的 Item 结构:
// {
//   "json": {
//     "error": {
//       "message": "Request failed with status 429",
//       "name": "NodeApiError",
//       "httpCode": 429
//     }
//   }
// }

2. Error Trigger 全局捕获

graph TB
    subgraph "正常工作流"
        T[Trigger] --> A[节点 A] --> B[节点 B] --> C[节点 C]
    end
    
    subgraph "错误处理工作流 (独立的)"
        ET[⚠️ Error Trigger
捕获任何工作流的错误] --> Parse[解析错误信息] Parse --> Log[📝 写入 Data Table] Parse --> Alert[🚨 Slack/Email 告警] Parse --> Retry[🔄 尝试自动恢复] end B -.->|"💥 异常"| ET style ET fill:#ef4444,stroke:#dc2626,color:#fff
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Error Trigger 输出的数据结构
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
{
  "json": {
    "execution": {
      "id": "exec_abc123",              // 失败的执行 ID
      "url": "https://n8n.../execution/abc123",  // 可直接点击查看
      "retryOf": null,                  // 如果是重试,引用原执行
      "mode": "trigger"                 // manual | trigger
    },
    "workflow": {
      "id": "1",
      "name": "天气机器人"               // 失败的工作流名称
    },
    "error": {
      "message": "Request failed: 429 Too Many Requests",
      "node": "HTTP Request",           // 报错的节点名
      "timestamp": "2026-04-09T12:00:00Z"
    }
  }
}

3. 优雅降级模式

graph TB
    API[调用外部 API] --> Check{成功?}
    
    Check -->|"✅ 成功"| Normal[正常处理]
    Check -->|"❌ 失败"| Fallback{降级策略}
    
    Fallback --> Cache["📦 使用缓存数据
(上次成功的结果)"] Fallback --> Default["📋 使用默认值
(预设的兜底响应)"] Fallback --> Queue["📬 加入重试队列
(稍后重试)"] style Fallback fill:#f59e0b,stroke:#d97706
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 优雅降级实现 (Code 节点)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

const apiResult = $input.first().json;

// 检查是否有错误
if (apiResult.error) {
  // 从 Data Table 读取缓存
  const cached = $('Data Table').first()?.json;
  
  if (cached && cached.cachedAt) {
    // 使用缓存数据,并标记为降级响应
    return [{
      json: {
        ...cached.data,
        _degraded: true,
        _degradedReason: apiResult.error.message,
        _cachedAt: cached.cachedAt
      }
    }];
  }
  
  // 缓存也没有,使用默认值
  return [{
    json: {
      message: "服务暂时不可用,请稍后再试",
      _degraded: true
    }
  }];
}

return [{ json: apiResult }];  // 正常流程

4. 多渠道告警

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 告警分级策略
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// P0 (紧急): 支付/关键流程中断
//   → Slack #alerts-critical + 短信/电话 + PagerDuty

// P1 (重要): API 连续失败 ≥ 5 次
//   → Slack #alerts + Email

// P2 (警告): 单次失败但已自动恢复
//   → Data Table 记录即可

// P3 (信息): 降级但仍可用
//   → 日志记录

下一步

Ep 27 将探索 Sub-Workflow 子工作流架构——将复杂逻辑拆分为可复用的模块化组件。