CI 流水线超时参数配置踩坑:官方文档三处口径不一致与上限无余量

CI 流水线超时参数配置踩坑:官方文档三处口径不一致与上限无余量

2026-10-05

给视频处理流水线做 CI 排障那天,我先后三次撞上”超时”这个词,每次含义都不同。第一次在官方 timeout 文档里读到”流水线最长 20 小时”,第二次在项目配置里看到别人写的 timeout: 43200s(12 小时),第三次从报错日志里翻出”连续 10 分钟无输出将触发超时”。

三处口径,三个数字。而我的流水线恰恰因为其中一处,把月免费额度的 60% 烧在了干等上。

这篇把三处口径的关系讲清楚,附上我踩过的坑和最终的四层对齐方案。

背景:一条会”跑满配置上限”的流水线

我的场景是一条视频处理流水线:本地 NAS 上传视频 → 云端跑 VAD+YOLO 智能截取 → 归档回本地。云端按核时计费,免费额度分两档:云原生开发(workspace)1600 核时/月,云原生构建(build)160 核时/月。8 核节点跑 1 小时就是 8 核时。

9 月额度烧得异常快。查 workspace/list 才发现:流水线以 workspace 形式跑了 20 次,平均 9.75 小时,20 × 9.75 × 8 ≈ 1560 核时——几乎精确等于 1600 核时的开发月额度。后来触发方式切到构建路径,额度一下子缩到 160 核时/月,只剩原来的 1/10。

不是”空转”烧的,是跑满配置上限烧的。罪魁就是配置里的 timeout: 43200s。

三处口径,三个数字

官方 timeout 文档里其实藏着三层完全不同的超时:

口径 数值 触发条件 能否配置
流水线超时 20h 整条流水线超时 ❌ 平台硬上限
Job 超时 默认 2h / 声明后 ≤12h Job 累计执行超时 ✅ timeout:
无输出超时 默认 10min(声明后=配置值) 连续无日志输出 ⚠️ 只能靠持续输出规避

第一层”流水线 20 小时”是平台硬上限,runner 日志里直接打印 maxPipelineRunTime: 20h,不可配置。

第二层才是配置项。语法是 timeout: 30m(支持 ms/s/m/h 单位),默认 2 小时,声明后最大不超过 12 小时。我项目里的 43200s 正好顶到 12 小时上限。

第三层最隐蔽:Job 连续 10 分钟无任何输出就触发超时,跟 timeout 配置无关,FAQ 明确说不能通过配置修改。长任务只要 10 分钟不打印日志就会被掐断。

三层超时口径对照

我踩的坑:12 小时空等

timeout: 43200s 是能生效的——平台允许最大 12 小时,配置就真的按 12 小时执行。实测每个 workspace 跑满 11.87 小时,8 核 × 12h = 96 核时。在开发额度(1600 核时/月)下这只是零头,但触发方式切到构建路径后,一次 12 小时空等就是构建月额度(160 核时)的 60%——烧穿只差一次。

这里有个反直觉点:超时参数不是”写进 yml 就完事”,它会真实执行,而且按配置上限烧满额度。平台没出 bug,是我把上限用满了。

更隐蔽的是无输出超时。流水线的主处理循环里有长时间无日志的段,10 分钟一到就被平台掐断。解决方法是加一个 30 秒心跳线程,持续打印处理进度,实测有效。

配额那边还有一个”无余量”的坑

超时之外,配额接口还有个单位陷阱:charge/quota 返回的 ci_in_sec 是核秒,不是核时。直接当核时用会差 3600 倍,÷3600 才是核时。

还有一件容易误判的事是”启动失败”。有次构建 7 秒就 error,我以为功能坏了。实际是预冻结机制:启动后每 5 分钟冻结一次用量,冻结量 = 5 分钟 × 节点规格(8 核 = 0.67 核时/次)。预冻结时可用额度不足,任务立即终止,连排队的机会都没有。这是额度耗尽的表现,不是故障。失败本身很便宜,prepare 阶段就 error,没过预冻结不计费。

还有月底清零:免费额度月底归零、不叠加至次月。额度耗尽后等次月即可,不用付费救急。

四层超时对齐方案

排障最终收敛成一套”四层对齐”:

流水线 20h(平台硬上限,不可配)
  > Job timeout(可配,≤12h)
  > 脚本软限(--max-minutes)
  > 无输出心跳(30s 持续输出,规避 10min 掐断)

我的最终配置:

  • timeout: 8400s(2.33 小时硬兜底,对齐脚本软限)
  • --timeout 0(空池即退,不再干等)
  • --max-minutes 120(脚本自身 2 小时软限)

关键是把 Job timeout 和脚本软限对齐:脚本挂住时烧满 stage 时长(8400s × 8 核 = 16 核时/路),两层不匹配会白白烧额度。

四层超时对齐

排查顺序(可直接照抄)

  1. 先读官方 timeout 文档,把三层口径装进脑子(1 分钟)
  2. 查配额:GET /{org}/-/charge/quota,核秒 ÷3600 = 核时
  3. 查在途冻结:GET /{org}/-/charge/volume,看 freeze_* 字段
  4. 读 runner 日志确认平台实测值:找 maxPipelineRunTime: 20h、配额大小、CPU/内存
  5. 对齐四层超时(上面那张图)
  6. 验证触发路径:构建接口的 sync 参数必须是字符串 "false",布尔值会报 400

总结

三处超时口径的关系一句话说清:流水线 20h 是天花板,Job timeout 是你能配的(≤12h),无输出 10min 是隐藏的侧门。真正烧额度的是”配置允许 + 任务真的跑满”,以及”脚本软限和 Job timeout 不匹配”。

超时参数一定会被执行,写进去之前先想清楚:这个值如果被跑满,成本是多少?我当时没想到 12 小时 × 8 核 = 96 核时是什么概念,现在记住了。

配额那边的教训同样直接:单位(核秒 vs 核时)、机制(5 分钟阶梯冻结 vs 连续消耗)、时间(月底清零)三个认知对齐之后,”额度怎么没了”这种问题基本不会再出现。

标签: CNB CI 超时配置