Skip to content

ci: Temporal Conformance's two test steps run under the stall guard (#4331) - #4337

Closed
os-zhuang wants to merge 1 commit into
mainfrom
claude/temporal-stall-guard-4331
Closed

ci: Temporal Conformance's two test steps run under the stall guard (#4331)#4337
os-zhuang wants to merge 1 commit into
mainfrom
claude/temporal-stall-guard-4331

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #4331

改了什么

Temporal Conformance (live PG + MySQL) job 的两个测试步骤原来裸跑 pnpm test,现在和 Test Core(ci.yml:153/165)一样包上 run-with-stall-guard,参数相同(--stall-minutes 10):

步骤 log
Run driver-sql suite against both live servers $RUNNER_TEMP/temporal-driver-sql.log
Run the non-SQL temporal backends under the skewed process zone $RUNNER_TEMP/temporal-non-sql.log

两步的 TZ 断言原样留在 guard 之前、不被包进去 —— 那个 node -e 必须能在任何测试启动前直接中断该步骤。已验证 TZ=UTC 时 step 在 bash -e 下于断言处退出 1,guard 根本不会被执行到。

10 分钟的取值:该 job 健康跑完是 3–4 分钟,10 分钟静默不可能是"慢",与 Test Core 保持一致。

关于 issue 里提的第二种形态 —— 结论是 guard 已经覆盖,不需要新检测器

issue 猜测「如果 guard 目前只盯输出静默,这一形态正好覆盖」,这个判断是对的,而且我实测确认了,没有只靠读代码:

  • 形态 A(run 2:五个包全部 Done、进程不退出、零输出) —— 子进程还活着但不再产出字节,watchdog 只看静默、不看子进程死活,所以照样在阈值处触发:判 stall → 杀整个进程组 → exit 75。判决里引用的 last line 正是 turbo 的完成摘要。
  • 形态 B(顶层命令已退出、但残留孙进程仍握着 stdout/stderr 管道) —— guard 走的是 child.on('exit') 而不是 'close',所以是立即返回子进程真实退出码(实测 elapsed 0s),不会被泄漏的管道句柄吊住。这一条本来就是对的,我把它写进注释免得日后有人"顺手"改成 'close' 把洞开出来。

顺带确认退出码没被吞:红套件穿过 guard 仍然 exit 1。

因此脚本里没有加任何兜底逻辑,唯一的改动是判决文案:原文只描述了 mid-suite 那一种形态(「This is the #4250 failure mode」),在 post-Done 形态下会把人引去找一个根本不存在的卡死测试文件。现在它同时点名两种形态,并说明用 last line 来区分。

验证

CI 配置改动,靠机械验证而非跑真套件(guard 本身在 Test Core / Dogfood / 两个 nightly 上已在跑):

  • YAML 解析通过;两个 step 的 run body 过 bash -n
  • 把 step body 抽出来、用一个打印 argv 的假 pnpm 执行,确认 -- 之后传给 guard 的参数与原来的 pnpm 调用逐字相同(含第二步那串多行 --filter 续行),TZ 断言仍先跑并打印 skewed zone。
  • TZ=UTC 时步骤在断言处退出 1,不进 guard。
  • 形态 A / 形态 B / 红套件三个用例按上文实测。

未加 check-test-completeness.mjs 后置步骤(Test Core 和 Dogfood 有):issue 没有要求,是否适用于这两个套件的输出形态需要单独判断,不在本 PR 范围内扩。

changeset 为空 frontmatter(CI-only,releases nothing),沿用 test-core-stall-guard.md / stall-guard-rollout.md 的惯例。

🤖 Generated with Claude Code

…4331)

Both test steps in the Temporal Conformance (live PG + MySQL) job ran
`pnpm test` bare, so a stall in either one had nothing to declare it: the
job sat in_progress until its 30-minute timeout and ended as "The
operation was canceled" — a red carrying no failing test, on PRs whose
diff had nothing to do with the packages under test. #4331 recorded two
such runs on one PR, both on the non-SQL step, ~4 and ~7× that job's
normal 3-4 minute runtime.

Both steps now wrap their pnpm invocation in run-with-stall-guard with
the same `--stall-minutes 10` as Test Core (ci.yml:153/165), so silence
past the limit becomes a labeled fast failure naming the last line seen.
Each step keeps its TZ assertion ahead of the guard, unwrapped: the zone
check must still abort the step before any test runs.

The guard needed no new detector for the second shape #4331 saw — all
five packages reporting Done and the process then never exiting.
Verified against both shapes directly: a child that prints a completion
summary and then never exits or emits is declared stalled at the limit
and its process group killed (exit 75), and a child that exits while a
silent grandchild still holds the stdio pipes open returns immediately
rather than blocking the guard — `child.on('exit')`, not 'close'. Only
the verdict text changed: it named just the mid-suite shape and sent
readers hunting a hung test file that, in the post-Done shape, does not
exist.

Closes #4331

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 31, 2026 6:42am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation ci/cd tooling size/s labels Jul 31, 2026
@os-zhuang

Copy link
Copy Markdown
Contributor Author

关掉 —— 本 PR 已被 #4335 取代,那边先合入了 main。

两边是并行做同一个 #4331:ci.yml 的改动在命令层面逐字一致(同样两处 wrapper、同样的 temporal-driver-sql.log / temporal-non-sql.log、同样 --stall-minutes 10、TZ 断言同样留在 wrapper 之外),连 changeset 文件名都撞了。没有需要从这边捡回去的东西。

scripts/run-with-stall-guard.mjs 那处冲突不是重复劳动,而是 #4341 在我之后重写了同一段 banner —— 它加的 /proc 采样 + SIGUSR2 栈取证,比本 PR 里那点判决文案改动强得多,本 PR 的这部分同样不必保留。

留档两条本 PR 里核实过的事实,供 #4250 / #4331 后续参考:

  1. 两次 stall 的归属:CI: Temporal Conformance 的两个 skewed-zone 步骤没挂 run-with-stall-guard,mid-suite stall 烧满 30 分钟才被 cancel #4331 记录的两次都发生在 non-SQL 那一步(run 1 卡在 core 的 kernel.test,run 2 是"五个包全部 Done"),driver-sql 步没有被观察到 stall 过。已合入的注释在 driver-sql 步写的是 "Both of this job's test legs have hit the same nondeterministic stall",与它自己在 non-SQL 步补的 "the occurrence was on THIS leg" 相互矛盾。
  2. guard 的退出路径必须是 child.on('exit') 而不是 'close':实测确认,顶层命令退出、但残留孙进程仍握着 stdout/stderr 管道时,'exit' 立即返回真实退出码(elapsed 0s);换成 'close' 会让 guard 自己被泄漏句柄吊住 —— 正好是 CI: Temporal Conformance 的两个 skewed-zone 步骤没挂 run-with-stall-guard,mid-suite stall 烧满 30 分钟才被 cancel #4331 run 2 那种形态。目前没有注释挡着有人"顺手"改掉它。

另外实测确认过:issue 里猜测的"只盯输出静默能否覆盖『全部 Done 后不退出』"成立 —— watchdog 不看子进程死活,该形态照样在阈值处判 stall、杀进程组、exit 75。

@os-zhuang os-zhuang closed this Jul 31, 2026
@xuyushun441-sys
xuyushun441-sys deleted the claude/temporal-stall-guard-4331 branch July 31, 2026 07:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd documentation Improvements or additions to documentation size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CI: Temporal Conformance 的两个 skewed-zone 步骤没挂 run-with-stall-guard,mid-suite stall 烧满 30 分钟才被 cancel

1 participant