n8n 2.30.5 故障注入基线:100 次执行如何被正确分类
我们在断网容器中执行同一工作流 100 次,主动注入 4 次 429 和 4 次超时。结果没有意外故障,但真正有价值的是两次失败的实验脚本如何暴露了 CLI 和解析假设。
PUBLIC EVIDENCE PACKAGE
不要只读结论,下载原始记录。
先说明 92% 不是什么
100 次执行中有 92 次成功、4 次被主动标记为 HTTP 429、4 次被主动标记为超时,意外故障为 0。这里的 92% 不是 n8n 的可靠性,也不是成功率基准,因为 8 次失败是工作流代码按协议故意制造的。
这项基线只验证一件事:固定版本的 n8n 执行同一工作流时,实验收集器能否把成功、预设 429、预设超时和意外故障分开,并为每次输出留下哈希与耗时。
固定的测试环境
| 项目 | 本次值 | 证据位置 |
|---|---|---|
| n8n | 2.30.5 | manifest.json |
| 镜像摘要 | sha256:450853cd…a6dc8c6f | manifest.json |
| Docker Server | 28.3.3 | summary.json |
| 平台 | darwin / arm64 | summary.json |
| 网络 | 容器 network none | 运行脚本 |
| 工作流 | Manual Trigger → Code | workflow.json |
| 执行次数 | 100 | runs.csv |
所有执行使用同一个临时 n8n 数据卷和隔离容器。每次通过 CLI 启动一个新的工作流执行,容器不访问外部网络。测试结束后,容器和数据卷被删除。
故障是怎样注入的
执行序号通过测试环境变量进入 Code 节点。序号为 25 的倍数时抛出 INJECTED_TIMEOUT;否则,当序号为 20 的倍数时抛出 INJECTED_HTTP_429。因为超时条件在前,第 100 次虽然同时满足两个条件,仍应归类为超时。
| 预设分支 | 运行序号 | 实际记录 |
|---|---|---|
| HTTP 429 | 20、40、60、80 | 4 次 injected_http_429 |
| 超时 | 25、50、75、100 | 4 次 injected_timeout |
| 正常 | 其余序号 | 92 次 success |
| 意外故障 | 任意非预设错误 | 0 次 |
逐次 CSV 保存执行序号、CLI 退出码、分类、CLI 总耗时、工作流内部耗时和原始输出 SHA-256。公开文件不包含密钥、Cookie、个人数据、本机路径或原始日志。
两种耗时不能混在一起
工作流内部耗时从 n8n 返回的 startedAt 和 stoppedAt 计算;CLI 总耗时从宿主机启动 n8n execute 到进程退出计算。两者回答的是不同问题。
| 指标 | 最小值 | P50 | P95 | 最大值 |
|---|---|---|---|---|
| 工作流内部耗时 | 799 ms | 934 ms | 1,097 ms | 1,337 ms |
| CLI 总耗时 | 2,785.30 ms | 3,363.33 ms | 4,062.74 ms | 6,555.59 ms |
第 59 次 CLI 总耗时达到 6,555.59 ms,但工作流状态仍为成功。若只公布平均值,这个长尾会消失;因此后续实验保留逐次记录并报告 P50、P95 和最大值。
第一次失败:废弃参数被当成成功
最初脚本使用 n8n execute --file 直接运行 JSON。n8n 2.30.5 的 CLI 帮助仍显示该参数,但已经标记 DEPRECATED,并要求使用工作流 ID。实际执行返回“--id has to be set”,CLI 进程的状态没有被原脚本正确识别,于是前 28 次被错误打印为 success。
我们中止了这批无效运行,没有生成 CSV。修正方式是先用 import:workflow 把固定工作流导入临时数据卷,再用 n8n execute --id 执行。这一失败比一次顺利跑完更有价值:执行器接口本身也必须进入版本检查。
第二次失败:字符串搜索读到了源码
修正 ID 后,原始执行 JSON 会包含 Code 节点源码。旧解析器在整段文本里搜索 INJECTED_TIMEOUT,因此从第 1 次开始就错误命中了源码中的故障名称。
第二批运行也被中止。最终解析器先提取完整执行 JSON,再读取顶层 status、resultData.error.description、message 和 stack;正常与故障单次调试都通过后,才从 1 开始第三批 100 次运行。
环境变量开关只用于合成序号
n8n 2.30.5 默认阻止 Code 节点读取环境变量。本实验显式设置 N8N_BLOCK_ENV_ACCESS_IN_NODE=false,让公开的运行序号进入节点。这不是生产安全建议,也没有把密钥放进环境变量。
真实工作流应优先通过输入数据、凭据系统或受控变量传递业务值。不能为了方便读取密钥而照搬本实验开关。
这项结果能证明什么
- 固定镜像和工作流在本次环境中完成了 100 次可分类执行;
- 4 次 429、4 次超时和 92 次成功与预设序号完全一致;
- 没有出现第五种意外状态;
- 证据收集器能区分 CLI 总耗时与工作流内部耗时;
- 输出哈希允许后续检查记录是否被替换。
还不能证明什么
- 不能证明 n8n 在生产环境中的总体可靠性;
- 没有请求真实第三方 API,429 与超时都是合成错误;
- 没有测试自动重试、退避、错误工作流、告警或恢复;
- 没有测试并发、数据库竞争或常驻服务延迟;
- 100 次样本不足以估计低概率生产故障。
下一项实验会在本基线之上接入本地可控 HTTP 服务,真实返回 429、500 和延迟响应,再比较有限重试与无重试分支。
来源与核验日期
- AI Brief Note 原始实验摘要:版本、分类计数、P50/P95 与限制。 · 已核验 · generated_from_100_recorded_runs_2026-07-23
- n8n 官方 CLI 文档:工作流导入、导出与执行命令。 · 已核验 · official_site_checked_2026-07-23
- n8n 官方 Code 节点文档:JavaScript 执行方式和运行模式。 · 已核验 · official_site_checked_2026-07-23