执行摘要
- 一句话:夜间 Ascend 检查步骤增加日志等待与诊断
- 推荐动作:建议 CI 维护者精读这次改动,它示范了一种成本极低的「先吸收延迟、再落证据」的 flaky 处理策略:有界轮询加
-s 判定、诊断命令挂 || true、路径收敛到变量,都值得复用到其他 Ascend 夜间作业的同类检查步骤。重点看三处设计决策:(1) 60s 上限与 10s 间隔的取舍;(2) 诊断只打尾部 4096 字节;(3) 把日志路径抽成 LOG 变量。若追求更彻底,可进一步讨论把检查输入改为 Actions stdout、或在训练脚本里给 tee 加 stdbuf -oL / 追加后 sync,以及把诊断文件作为 artifact 上传。同时务必在团队内同步:该作业要恢复全绿还需在 verl-project/verl-ascend-recipe 仓库重新生成 baseline_qwen3_vl_8b_Instruct_fsdp2_npu.txt,这不是本仓库能解决的。
功能与动机
PR body 给出明确的失败签名:9 天内复现 3 次,最近一次为 run 34506778944 / job 102970797276。原文描述「training completes all 15/15 steps and every step:N line is present in the Actions-captured stdout, but the file tee'd by tests/special_npu/run_qwen3_vl_8b_Instruct_fsdp2_npu.sh is empty when the checking step reads it ~6 s later」,于是 check_npu.py 抛 ValueError: 日志中无有效step,作业转红,而训练步骤本身退出码为 0。作者明确认定这是「runner-side file content loss/delay on the k8s custom-container runner, not a verl bug」,因此选择先吸收延迟、再把下一次复现的证据(missing / empty / truncated)固定下来,而不是盲目重跑。
实现拆解
- 入口定位:改动集中在 .github/workflows/nightly_ascend.yml 中
Running nightlyCI_grpo_qwen3_vl_8b_Instruct_fsdp2_vllm_ascend checking script 这一步(该作业仅在 schedule: '0 17 * * *' 触发,PR 阶段不执行)。步骤开头 cd /root/.cache/nightly_log/ 保持不变,新增局部变量 LOG=run_qwen3_vl_8b_Instruct_fsdp2_npu/run_qwen3_vl_8b_Instruct_fsdp2_npu.log,把原先散落硬编码的路径收敛到一处,避免等待、诊断、校验三处路径漂移。
- 有界等待吸收延迟:新增
for i in $(seq 1 6) 轮询,用 [ -s "$LOG" ] 判断日志「存在且非空」即 break,否则 echo 提示并 sleep 10,上限 60s。选择 60s 是对「失败路径不能无限阻塞」与「正常路径几乎不付代价」之间的折中:日志正常时循环一次即退出。
- 诊断信息前置:等待结束后无条件打印
ls -l "$LOG"、wc -c "$LOG"、tail -c 4096 "$LOG",三条命令都挂 || true,保证诊断命令自身失败不会把这一步判红。三条命令分别回答「文件是否存在」「字节数是否为 0」「内容是否被截断」,把原本不透明的 ValueError 变成可定性的证据;tail -c 4096 只取尾部,避免日志巨大时污染 Actions 输出。
- 调用口径统一:把
python check_npu.py --log run_qwen3_vl_8b_Instruct_fsdp2_npu/run_qwen3_vl_8b_Instruct_fsdp2_npu.log --base baseline.txt 改为 --log "$LOG",行为等价但后续改动只需改一处;check_npu.py 与 baseline 仍通过 curl --fail --location --retry 3 从 ${ASCEND_RECIPE_BASELINE_URL} 拉取,本 PR 未触碰。
- 测试与配套:无自动化测试(调度型 job 不在 PR 上运行),作者本地验证了 YAML 语法与内嵌 shell 的
bash -n,并确认新增命令只用容器镜像内的 POSIX 工具。作者同时说明:即使日志能被解析,该作业仍会卡在显存检查上——recipe 仓库基线文件仍是 #7428 之前的 actor/perf/max_memory_allocated_gb: 45.43,而 #7428 之后的运行稳定在约 41.47 GB(阈值 ±1 GB),该基线只能在 verl-project/verl-ascend-recipe 侧重新生成,无法在本仓库修复。
关键文件:
.github/workflows/nightly_ascend.yml(模块 夜间流水线;类别 infra;类型 ci-pipeline;符号 Running nightlyCI_grpo_qwen3_vl_8b_Instruct_fsdp2_vllm_ascend checking script, LOG): 唯一改动文件,新增 60s 有界等待与 ls -l / wc -c / tail -c 4096 诊断,并把 check_npu.py 的 --log 参数改为变量引用
tests/special_npu/run_qwen3_vl_8b_Instruct_fsdp2_npu.sh(模块 冒烟脚本;类别 test;类型 context-only): 未在本 PR 中修改,但它就是产生 tee 日志("$@" | tee $LOG_DIR/$SCRIPT_NAME.log)的脚本,是本次空日志现象的写入端,理解风险边界必须读它
关键符号:nightlyCI_grpo_qwen3_vl_8b_Instruct_fsdp2_vllm_ascend checking script(有界等待 + 诊断), LOG 非空轮询循环(seq 1 6 / sleep 10), check_npu.py 调用(--log "$LOG" --base baseline.txt)
关键源码片段
.github/workflows/nightly_ascend.yml
唯一改动文件,新增 60s 有界等待与 ls -l / wc -c / tail -c 4096 诊断,并把 check_npu.py 的 --log 参数改为变量引用
# .github/workflows/nightly_ascend.yml —— qwen3_vl 夜间检查步骤(合并后形态)
- name: Running nightlyCI_grpo_qwen3_vl_8b_Instruct_fsdp2_vllm_ascend checking script
run: |
cd /root/.cache/nightly_log/
# 把日志路径提成变量:等待循环、诊断、check_npu.py 三处共用,
# 避免原先「硬编码路径 + 新增等待」产生两份不一致的字符串
LOG=run_qwen3_vl_8b_Instruct_fsdp2_npu/run_qwen3_vl_8b_Instruct_fsdp2_npu.log
# 有界等待:tee 出来的日志可能晚于训练步骤可见(k8s 自定义容器 runner)
# 最多轮询 6 轮、每轮 10s,即 60s 上限;-s 表示「存在且非空」即刻提前退出,
# 因此日志正常时这里只付出一次 test 的代价
for i in $(seq 1 6); do
if [ -s "$LOG" ]; then
break
fi
echo "attempt $i: $LOG missing or empty, waiting 10s..."
sleep 10
done
# 无论等到与否都打印诊断,用于区分「文件缺失 / 存在但为空 / 内容被截断」;
# 末尾 || true 保证诊断命令自身失败不会把这一步判红
ls -l "$LOG" || true
wc -c "$LOG" || true
tail -c 4096 "$LOG" || true # 只取尾部,避免大日志污染 Actions 输出
# 校验脚本与基线仍从 ascend recipe 仓库拉取,本 PR 未改动
curl --fail --location --retry 3 --output check_npu.py "${ASCEND_RECIPE_BASELINE_URL}/check_npu.py"
curl --fail --location --retry 3 --output baseline.txt "${ASCEND_RECIPE_BASELINE_URL}/a2/nightly_log/run_qwen3_vl_8b_Instruct_fsdp2_npu/baseline_qwen3_vl_8b_Instruct_fsdp2_npu.txt"
# 原先这里是硬编码的同一路径字符串,现在统一走 $LOG,
# 后续再调路径只需改一处;check_npu.py 抛 ValueError 时也就
# 能和上面的 ls -l / wc -c 诊断直接对上同一个文件
python check_npu.py --log "$LOG" --base baseline.txt
评论区精华
本次 PR 实质讨论极少:只有 wucong25 给出一个 APPROVED 且 review body 为空的批准,没有行内 review 评论。有价值的信息几乎全部来自 PR 描述本身:(1) 明确「不是 verl bug,而是 runner 侧文件可见性」的定性,避免团队误入训练代码排查;(2) 主动披露基线漂移这一「合并后仍红」的已知后果,并声明超出本仓库修复范围;(3) 披露 AI 辅助(Kimi)并声明提交者已逐行 review;(4) 说明重复工作检查结论——未找到针对 nightly_ascend / check_npu /「nightly log empty」的开放 PR。由于无人在评审中质疑等待时长、诊断持久化方式或根因归属,这些点仍属于「已披露但未论证」的状态。
- 只有一次无评论批准,关键取舍未经评审论证 (design): 变更以批准合并;这些取舍当前属于「已披露、未论证」,需要靠下一次夜间运行的实际证据来确认。
- PR 描述自述的遗留问题:recipe 仓库显存基线未重生成 (other): 未解决,超出本仓库范围;需要在 recipe 仓库重新生成 baseline_qwen3_vl_8b_Instruct_fsdp2_npu.txt 才能让该作业真正转绿。
风险与影响
- 风险:
- 等待窗口固定,可能仍不够:60s 上限基于「~6s 后读到空文件」的现象外推,若 runner 落盘更慢,
check_npu.py 依旧会以同样的 ValueError 失败,只是多花 60s;反过来在日志确实为空时,这一步会稳定多耗 60s,拉长夜间作业总时长。
- 根因未消除:
tee 内容丢失发生在 runner 侧或训练脚本 "$@" | tee $LOG_DIR/$SCRIPT_NAME.log 的管道上,本 PR 只是吸收延迟并采集证据,没有改用 stdbuf / sync / 直接以 Actions stdout 作为检查输入;同一 runner 上的其他 Ascend 夜间作业(如 qwen3_5_2b 等链路)若有相同写日志模式,仍可能复现。
- 诊断信息不进制品:
ls -l / wc -c / tail -c 4096 只写进当前步骤日志,未上传 artifact;如果该步骤本身因 runner 异常被截断,证据可能一起丢失。
- 合并后仍会红的预期偏差:由于基线仍为 45.43 GB,而当前实跑约 41.47 GB(阈值 ±1 GB),即使日志等待逻辑生效,作业仍会在显存检查处失败;这容易被误读为「本 PR 无效」。
- 缺少自动化验证:改动只在
schedule: '0 17 * * *' 触发,PR 期间无法回归;YAML 缩进或 shell 兼容性问题要等到下一次夜间运行才暴露,属于典型的 CI-only 变更盲区(bash -n 只能覆盖语法,覆盖不了 runner 行为)。
- 影响:影响面局限在 CI 层面:不触碰任何训练、rollout、checkpoint 代码路径,对最终用户与训练正确性零影响。对团队而言,收益是双重的——正常路径几乎无额外开销(日志非空时循环一次即退出),失败路径则把「不透明的 ValueError」升级为可定性的文件状态证据,直接降低夜间作业的排障成本,也有助于确认问题到底出在 runner 还是训练脚本。潜在负面影响集中在可观测性预期上:作业变红时,读者需要额外理解「日志检查已加固、显存基线尚未更新」这两件事,否则容易重复排查。对 Ascend 夜间 CI 的稳定性治理来说,这是一次低风险、可回滚的增量改进,但并非该作业恢复全绿的最后一步。
- 风险标记:CI-only 变更无自动化验证, 等待窗口固定 60s 可能不足, 根因未消除(runner 侧日志可见性), 跨仓库基线漂移导致作业仍红, 诊断信息未上传 artifact
关联脉络
- PR #7799 [ci] fix: nightlyCI_grpo_qwen3_5_2b_fsdp2_vllm_ascend: 同样修改 .github/workflows/nightly_ascend.yml,属于 Ascend 夜间流水线的连续维护,本 PR 的日志等待与诊断思路可直接复用到该作业。
- PR #7827 [megatron, ci] fix: configure Megatron integration in Ascend images and tests: 同期 Ascend CI/镜像基础设施改动(Ascend Dockerfile + Ascend 单测工作流),与本 PR 同属 Ascend 流水线可运行性治理链路。
- PR #7428 (标题未在本次上下文中提供): PR 描述直接引用:该 PR 之后 qwen3_vl 夜间作业的显存从 45.43 GB 降到约 41.47 GB,导致 recipe 仓库基线过期、作业持续红,是本 PR 之外的关键依赖。
参与讨论