Skip to content

fix(cli): Keep serve health responsive before runtime load - #6013

Merged
wenshao merged 18 commits into
mainfrom
codex/serve-health-first-runtime
Jun 30, 2026
Merged

fix(cli): Keep serve health responsive before runtime load#6013
wenshao merged 18 commits into
mainfrom
codex/serve-health-first-runtime

Conversation

@doudouOUC

Copy link
Copy Markdown
Collaborator

What this PR does

This PR keeps the serve fast path responsive for the first /health probe by deferring the heavier runtime graph until after a successful bootstrap health response has been flushed. It also gives the deferred path a fallback timer so the runtime still starts when no health probe arrives, and keeps the headless YOLO startup warning on the fast path without dynamically importing the core runtime before health can respond.

Why it's needed

PR #5995 removes accidental pre-listen runtime closure from the serve bundle, but end-to-end /health can still be delayed by work that runs immediately after the listener is ready. The runtime import/evaluation path and the headless warning's core import can monopolize the event loop before the first health response is observed, so clients can still wait around the old startup duration even though processToListenMs is low.

Reviewer Test Plan

How to verify

Start from a build that includes PR #5995 and run qwen serve --hostname 127.0.0.1 --port <free-port> --workspace /tmp --no-web, then poll GET /health immediately after process start. The first successful response should come from the bootstrap app with {"status":"ok"} before runtime routes are mounted, while the runtime should still mount shortly afterward via the health-triggered start or the fallback timer. Reviewers can also confirm that no health probe still starts runtime after the fallback delay, and that closing a handle before the first health response does not start runtime during shutdown.

Evidence (Before & After)

Before: on the remote Linux verification host, PR #5995 lowered processToListenMs to roughly 200-300ms but /health still took roughly 1.6s median because post-listen runtime work and the headless warning import could block the event loop before the first health response. After: with this follow-up applied and bundled, the remote benchmark returned first /health responses in 220, 244, 266, 282, and 287ms for node dist/cli.js; the final local bundled benchmark returned 234, 122, 128, 135, and 126ms with a 128ms median.

Tested on

OS Status
🍏 macOS ✅ tested
🪟 Windows ⚠️ not tested
🐧 Linux ✅ tested

Environment (optional)

macOS local PR worktree with Node v26.0.0 and npm 11.12.1. Validation included npm install (which ran the repository prepare/build/bundle flow), npm run check:serve-fast-path-bundle, npm run typecheck, cd packages/cli && npx vitest run src/serve/run-qwen-serve.test.ts -t "runQwenServe runtime startup failures", cd packages/cli && npx vitest run src/serve/fast-path.test.ts src/utils/headlessSafetyWarnings.test.ts, and a bundled dist/cli.js /health first-response benchmark. Linux validation was performed on the remote startup-performance host during the investigation using the same bundled benchmark shape on top of PR #5995.

Risk & Scope

  • Main risk or tradeoff: the serve fast path now has a small bootstrap window where /health is intentionally available before the full runtime graph is mounted, so clients that immediately call non-health runtime routes can still observe the existing bootstrap "runtime starting" response until runtime mounting completes.
  • Not validated / out of scope: this PR does not optimize all runtime module evaluation after health succeeds, does not change non-fast-path embedded startup semantics, and does not retarget away from PR fix(cli): Guard serve fast-path bundle closure #5995 until that PR merges.
  • Breaking changes / migration notes: no user-facing CLI flags or API response schemas change.

Linked Issues

Follow-up to #5995.

中文说明

What this PR does

这个 PR 让 serve fast path 在首次 /health 探活时保持可响应:成功的 bootstrap health 响应 flush 之后,才启动较重的 runtime graph。它同时保留 fallback timer,确保没有 health 探活时 runtime 仍会启动,并让 headless YOLO 启动警告留在 fast path 上,但不再为了这个警告在 health 可响应前动态导入 core runtime。

Why it's needed

PR #5995 移除了 serve bundle 中意外的 pre-listen runtime 闭包,但端到端 /health 仍可能被 listener ready 之后立即执行的工作拖慢。runtime import/evaluation 路径以及 headless warning 的 core import 都可能在首次 health 响应被客户端观察到前占住事件循环,所以即使 processToListenMs 已经很低,客户端仍可能等待接近旧启动耗时。

Reviewer Test Plan

How to verify

基于包含 PR #5995 的构建启动 qwen serve --hostname 127.0.0.1 --port <free-port> --workspace /tmp --no-web,然后在进程启动后立即轮询 GET /health。首次成功响应应来自 bootstrap app,返回 {"status":"ok"},且发生在 runtime routes mount 之前;之后 runtime 应通过 health 触发启动或 fallback timer 正常 mount。Reviewer 也可以确认没有 health 探活时 runtime 会在 fallback 延迟后启动,并确认 handle 在首次 health 前关闭时不会在 shutdown 期间再启动 runtime。

Evidence (Before & After)

Before:在远程 Linux 验证机器上,PR #5995processToListenMs 降到约 200-300ms,但 /health median 仍约 1.6s,因为 listen 后的 runtime work 和 headless warning import 仍可能在首次 health 响应前阻塞事件循环。After:叠加这个 follow-up 并打包后,远程 benchmark 中 node dist/cli.js 的首次 /health 响应为 220、244、266、282、287ms;最终本地 bundled benchmark 的结果为 234、122、128、135、126ms,中位数 128ms。

Tested on

OS Status
🍏 macOS ✅ tested
🪟 Windows ⚠️ not tested
🐧 Linux ✅ tested

Environment (optional)

macOS 本地 PR worktree,Node v26.0.0,npm 11.12.1。验证包括 npm install(触发仓库 prepare/build/bundle 流程)、npm run check:serve-fast-path-bundlenpm run typecheckcd packages/cli && npx vitest run src/serve/run-qwen-serve.test.ts -t "runQwenServe runtime startup failures"cd packages/cli && npx vitest run src/serve/fast-path.test.ts src/utils/headlessSafetyWarnings.test.ts,以及 bundled dist/cli.js/health 首响 benchmark。Linux 验证是在远程启动性能机器上,调查过程中基于 PR #5995 用同样的 bundled benchmark 形态完成的。

Risk & Scope

  • Main risk or tradeoff: serve fast path 现在会有一个很短的 bootstrap 窗口,/health 会在完整 runtime graph mount 前可用;如果客户端立刻调用非 health runtime 路由,仍会看到现有 bootstrap 的 "runtime starting" 响应,直到 runtime mount 完成。
  • Not validated / out of scope: 这个 PR 不继续优化 health 成功后的所有 runtime module evaluation,不改变非 fast-path embedded startup 语义,也不会在 fix(cli): Guard serve fast-path bundle closure #5995 合并前脱离该 PR 重新 retarget。
  • Breaking changes / migration notes: 不改变用户可见 CLI flags 或 API 响应 schema。

Linked Issues

#5995 的 follow-up。

@doudouOUC

Copy link
Copy Markdown
Collaborator Author

E2E / startup validation report

Branch: codex/serve-health-first-runtime, stacked on fix/acp-prelisten-bundle-guard from PR #5995.

Validation commands run in /tmp/qwen-health-first-pr:

  • npm install completed successfully and ran the repository prepare flow, including build and bundle.
  • npm run check:serve-fast-path-bundle completed with Serve fast-path bundle closure check passed.
  • npm run typecheck completed successfully.
  • cd packages/cli && npx vitest run src/serve/run-qwen-serve.test.ts -t "runQwenServe runtime startup failures" passed: 1 file, 20 tests passed, 51 skipped by filter.
  • cd packages/cli && npx vitest run src/serve/fast-path.test.ts src/utils/headlessSafetyWarnings.test.ts passed: 2 files, 65 tests passed.

Bundled /health first-response benchmark using node dist/cli.js serve --hostname 127.0.0.1 --port <fixed-free-port> --workspace <tmpdir> --no-web and immediate polling of GET /health:

  • Local final branch results: 234ms, 122ms, 128ms, 135ms, 126ms; median 128ms.
  • Remote Linux investigation results with the same bundled benchmark shape on top of PR fix(cli): Guard serve fast-path bundle closure #5995 plus this follow-up: 220ms, 244ms, 266ms, 282ms, 287ms for dist/cli.js.

Expected behavior confirmed: the bootstrap app can return the first healthy /health response before the full runtime graph mounts, while runtime still starts after the health response or via fallback when no health probe arrives.

@doudouOUC
doudouOUC marked this pull request as ready for review June 29, 2026 12:55
Copilot AI review requested due to automatic review settings June 29, 2026 12:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@qwen-code-ci-bot

qwen-code-ci-bot commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓ — all required sections present with bilingual translation.

On direction: this is a well-motivated performance optimization that directly follows up on PR #5995. Keeping the serve health endpoint responsive before the heavy runtime graph loads is a clear win for orchestrators and health-check-based deployments. The approach — defer runtime until the first /health response flushes, with a fallback timer — is the right pattern for this problem. Aligned with the project's performance goals.

On approach: the scope feels right for the stated goal. Each piece serves a clear purpose: the deferRuntimeUntilFirstHealth flag, the onHealthServed callback, the fallback timer, the shutdown cancellation, and the headlessSafetyWarnings import removal. The createDelegatingServeApp changes that allow non-bootstrap routes to trigger runtime start (with auth gating) handle the edge case where a client skips health and goes straight to a session endpoint — good defensive design without being speculative. No drive-by refactors or scope creep detected.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓ — 所有必需章节齐全,含双语翻译。

方向:这是一个动机明确的性能优化,直接跟进 PR #5995。在重型 runtime graph 加载前保持 serve health endpoint 可响应,对编排器和基于健康检查的部署是明确的收益。延迟 runtime 直到首次 /health 响应 flush、配合 fallback timer 的方案是解决这个问题的正确模式,与项目的性能目标一致。

方案:范围与目标匹配。每个组件都有明确用途:deferRuntimeUntilFirstHealth 标志、onHealthServed 回调、fallback timer、shutdown 取消逻辑、以及 headlessSafetyWarnings 的 import 移除。createDelegatingServeApp 的改动允许非 bootstrap 路由触发 runtime 启动(带 auth 验证),处理了客户端跳过 health 直接调用 session endpoint 的边界情况——良好的防御性设计,非投机性。未检测到无关重构或范围蔓延。

进入代码审查 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

qwen-code-ci-bot commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Code Review

Independent proposal before reading the diff: I'd have added a flag to runQwenServe that skips the immediate startRuntime() call, paired with a hook on the health handler to trigger it post-response. I'd also need a fallback timer for no-probe scenarios and shutdown cancellation. The headlessSafetyWarnings core import removal is a separate but related fast-path concern.

The PR's approach matches this and exceeds it — the delegating serve app now also handles request-triggered runtime starts for non-bootstrap routes (with auth gating), which I didn't initially consider but is clearly needed for clients that skip health probes.

No correctness bugs, security holes, or regressions found. The runSynchronousRequestGate pattern for auth-before-runtime is correct — Express bearer auth is synchronous, so the boolean flag approach works. Timer lifecycle management is thorough (clear on start, clear on shutdown, cancel on pre-startup close). The runtime-startup-errors.ts shared constant avoids string duplication.

Test coverage is comprehensive: 81 tests in run-qwen-serve.test.ts (7 new deferred-runtime tests covering health-first, dedup, route-triggered, auth-gated, fallback, close-before-health, close-after-health, close-running, and failure-no-retry) plus 71 tests in fast-path.test.ts, fast-path-open.test.ts, and headlessSafetyWarnings.test.ts. All passing.

Real-Scenario Testing

Bundled dist/cli.js with PR code, ran qwen serve --port 0 --hostname 127.0.0.1 --no-web --workspace /tmp:

qwen serve listening on http://127.0.0.1:45409 (mode=http-bridge, workspace=/tmp)
qwen serve: bound to workspace "/tmp"
qwen serve: startup timing: processToListenMs=96 runQwenServeToListenMs=26
qwen serve: bearer auth disabled (loopback default). Set QWEN_SERVER_TOKEN to enable.
[DAEMON] deferred runtime: scheduling fallback start in 1000ms
[DAEMON] deferred runtime: fallback timer fired, starting
qwen serve: session reaper started (interval 60000ms, idle threshold 1800000ms)
qwen serve: /acp WebSocket transport enabled on /acp

=== Health check 1 ===
{"status":"ok"}
HTTP 200 in 0.004239s

=== Health check 2 ===
{"status":"ok"}
HTTP 200 in 0.000772s

=== Capabilities ===
HTTP 200 — full features list returned

=== Health check after runtime start ===
{"status":"ok"}
HTTP 200 in 0.001081s

[DAEMON] received SIGTERM, draining
=== Done ===

Key observations:

  • processToListenMs=96 — fast listener startup
  • Fallback timer fires at ~1s when no health probe arrives during the initial window, then runtime starts normally
  • Health responses in 1–4ms once server is up
  • Clean shutdown via SIGTERM
  • No errors in any endpoint response

Unit test run (worktree, after build):

✓ src/serve/run-qwen-serve.test.ts (81 tests) 3231ms
  ✓ keeps health responsive before starting deferred runtime work  309ms
  ✓ starts deferred runtime on fallback when no health probe arrives  1006ms
  ✓ does not start deferred runtime after close before first health  1104ms
✓ src/serve/fast-path-open.test.ts (2 tests) 327ms
✓ src/utils/headlessSafetyWarnings.test.ts (7 tests) 3ms
✓ src/serve/fast-path.test.ts (62 tests) 285ms

Test Files  4 passed (4)
     Tests  152 passed (152)
中文说明

代码审查

独立方案:我会给 runQwenServe 加一个跳过立即 startRuntime() 的标志,配合 health handler 上的钩子在响应后触发。还需要 fallback timer 处理无探活场景,以及 shutdown 取消逻辑。headlessSafetyWarnings 的 core import 移除是相关但独立的 fast-path 优化。

PR 的方案匹配并超越了此方案——delegating serve app 还处理了非 bootstrap 路由触发的 runtime 启动(带 auth 验证),这是我最初没考虑到的,但对跳过 health 探活的客户端来说显然必要。

未发现正确性 bug、安全漏洞或回归。runSynchronousRequestGate 的 auth-before-runtime 模式正确——Express bearer auth 是同步的。Timer 生命周期管理周全。runtime-startup-errors.ts 共享常量避免了字符串重复。

实际场景测试

用 PR 代码 bundle 的 dist/cli.js 运行 qwen serve

  • processToListenMs=96 — listener 启动快
  • Fallback timer 在无 health 探活时 ~1s 后正常触发 runtime 启动
  • Health 响应 1-4ms
  • SIGTERM 干净关闭
  • 所有端点无错误

单元测试:4 个文件 152 个测试全部通过。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

qwen-code-ci-bot commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

This PR delivers exactly what it promises: the serve fast path stays responsive for the first health probe by deferring the heavy runtime graph, with a clean fallback timer for no-probe scenarios and proper shutdown cancellation.

Going back to my independent proposal — the PR's approach matches and exceeds it. The addition of request-triggered runtime starts (with auth gating) for non-bootstrap routes is a thoughtful touch that covers clients who skip health probes entirely. The headlessSafetyWarnings refactor to remove the core import is a clean companion change that keeps the fast path lightweight.

The implementation is straightforward despite the complexity of the problem space. Timer lifecycle is well-managed, edge cases (shutdown before health, shutdown after health, duplicate probes, auth failures, startup failures with no retry) are all covered by both code and tests. 152 unit tests pass. Real-scenario testing confirms the deferred runtime pattern works as designed — fallback timer fires at ~1s, health responds in single-digit milliseconds, clean SIGTERM handling.

The diff is focused: every change serves the stated goal. No drive-by refactors, no speculative features. The ~1190 additions are dominated by test code (~900 lines of new tests), which is the right ratio for a state-machine change like this.

Approving. ✅

中文说明

这个 PR 完全兑现了承诺:通过延迟重型 runtime graph,serve fast path 在首次 health 探活时保持可响应,同时为无探活场景提供干净的 fallback timer 和正确的 shutdown 取消逻辑。

回顾我的独立方案——PR 的方案匹配并超越了它。为非 bootstrap 路由添加请求触发的 runtime 启动(带 auth 验证)是一个周到的设计,覆盖了跳过 health 探活的客户端。headlessSafetyWarnings 移除 core import 的重构是一个干净的伴随改动,保持 fast path 轻量。

尽管问题空间复杂,实现直截了当。Timer 生命周期管理良好,边界情况(health 前关闭、health 后关闭、重复探活、auth 失败、启动失败不重试)都由代码和测试覆盖。152 个单元测试通过。实际场景测试确认 deferred runtime 模式按设计工作。

Diff 聚焦:每个改动都服务于目标。无无关重构,无投机性功能。~1190 行新增中约 900 行是测试代码——对于状态机变更来说这是正确的比例。

批准合并 ✅

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@doudouOUC doudouOUC self-assigned this Jun 29, 2026
@doudouOUC
doudouOUC requested review from wenshao and yiliang114 June 29, 2026 13:11

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Downgraded from Approve to Comment: CI still running.

— qwen3.7-max via Qwen Code /review

Comment thread packages/cli/src/serve/run-qwen-serve.test.ts
doudouOUC added a commit that referenced this pull request Jun 29, 2026
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

@qwen-code /review

@github-actions

Copy link
Copy Markdown
Contributor
_Qwen Code review request accepted. Review is queued in [workflow run](https://github.com/QwenLM/qwen-code/actions/runs/28375932842)._

Comment thread packages/cli/src/serve/run-qwen-serve.test.ts
Comment thread packages/cli/src/serve/run-qwen-serve.test.ts
Comment thread packages/cli/src/serve/run-qwen-serve.ts
Comment thread packages/cli/src/serve/run-qwen-serve.ts
doudouOUC added a commit that referenced this pull request Jun 29, 2026
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Comment thread packages/cli/src/utils/headlessSafetyWarnings.ts
Comment thread packages/cli/src/serve/run-qwen-serve.test.ts
Comment thread packages/cli/src/serve/run-qwen-serve.ts
Comment thread packages/cli/src/serve/run-qwen-serve.ts
Comment thread packages/cli/src/serve/run-qwen-serve.test.ts
Comment thread packages/cli/src/serve/run-qwen-serve.test.ts

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Downgraded from Approve to Comment: CI still running.

No critical issues found. The deferred-runtime startup mechanism is correctly implemented with proper timer lifecycle management and idempotency guards. Two non-blocking suggestions below.

— qwen3.7-max via Qwen Code /review

Comment thread packages/cli/src/serve/fast-path.ts Outdated
Comment thread packages/cli/src/serve/run-qwen-serve.test.ts
doudouOUC added a commit that referenced this pull request Jun 29, 2026
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Comment thread packages/cli/src/serve/run-qwen-serve.ts
Comment thread packages/cli/src/serve/run-qwen-serve.ts Outdated
Comment thread packages/cli/src/serve/run-qwen-serve.test.ts
doudouOUC added a commit that referenced this pull request Jun 29, 2026
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully. Qwen review aborted with an API error before posting comments. See workflow logs.

doudouOUC added a commit that referenced this pull request Jun 29, 2026
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Comment thread packages/cli/src/serve/fast-path.ts
doudouOUC added a commit that referenced this pull request Jun 29, 2026
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Comment thread packages/cli/src/serve/run-qwen-serve.test.ts
wenshao
wenshao previously approved these changes Jun 30, 2026
@wenshao

wenshao commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No critical issues found. The deferred-runtime startup mechanism is correctly implemented with proper timer lifecycle management and idempotency guards. All 147 tests pass and no new type errors were introduced. Three suggestions below for consideration.

— qwen3.7-max via Qwen Code /review

Comment thread packages/cli/src/serve/run-qwen-serve.ts
Comment thread packages/cli/src/serve/run-qwen-serve.ts
Comment thread packages/cli/src/serve/run-qwen-serve.ts

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@wenshao

wenshao commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

✅ Local real-daemon verification (maintainer)

Built a real bundled dist/cli.js from the PR head (a55a21740, on top of main which already contains #5995) in an isolated worktree, and drove a real qwen serve daemon under tmux. Authoritative evidence is the daemon's own debug-log markers + an A/B benchmark on the real binary, not client-side prints.

Environment: macOS (Darwin 25.5), Node v22.22.2 · isolated npm ci worktree · code-split bundle (the serve fast path lands in its own chunk) · loopback bind (--no-web, no token) · QWEN_DEBUG_LOG_FILE=1.

A/B method: Build A = PR as-is (deferRuntimeUntilFirstHealth: !parsed.open → ON). Build B = one-line mutation to deferRuntimeUntilFirstHealth: false (pre-PR baseline), re-bundled to a distinct chunk hash. Everything else identical.

1. First-/health latency — A/B on the real binary (12 trials each, 2 warm-ups discarded)

Build listen → first /health 200 (isolates the effect) spawn → first /health 200 defer markers
A — defer ON (this PR) median 3 ms (2–4) median 299 ms YES ✓
B — defer OFF (baseline) median 237 ms (233–261) median 529 ms NO ✓

~79× / −234 ms on the isolated listen→/health metric; the spawn→/health delta (−230 ms) corroborates (node cold-start is constant across A/B). In the baseline the first /health is blocked behind the runtime-graph mount (core module eval + bridge creation) that runs right after listen; this PR defers that until after the health response flushes. Direction & mechanism match the PR's claim (the absolute "before" is OS-dependent — larger on the Linux host cited in the PR).

2. Functional behavior — real daemon, tmux, daemon debug-log markers

Scenario Result
Health-triggered start first /health → 200 {"status":"ok"} in 4 ms; log: scheduling fallbackhealth served, scheduling start in 50mshealth timer fired, starting (+51 msFAST_PATH_RUNTIME_START_AFTER_HEALTH_MS); fallback did not fire ✓
Fallback (no probe) scheduling fallback start in 1000msfallback timer fired, starting (+1001 msFAST_PATH_RUNTIME_START_FALLBACK_MS); runtime starts with no probe ✓
Close before first health SIGTERM → received SIGTERM, drainingdeferred runtime: cancelled, server closed before startup; no runtime-start timer fired; clean drain ✓
First runtime route GET /workspace/agents200 (221 ms) with real data — not the bootstrap daemon_runtime_starting 503; it triggered the deferred start, awaited mount, and the runtime served it; runtime reached READY (session reaper started + /acp WebSocket transport enabled) ✓

3. Static checks & tests

  • Import-boundary guard npm run check:serve-fast-path-bundleServe fast-path bundle closure check passed (the fast path still does not pull core into the pre-listen closure).
  • Unit tests (vitest, real build): 147 passed across run-qwen-serve.test.ts (76), fast-path.test.ts, fast-path-open.test.ts, headlessSafetyWarnings.test.ts — incl. the 3 new deferred-runtime tests (keeps health responsive…, …fallback…, …close before first health).
  • Typecheck: cli exit 0, core exit 0.
  • Headless YOLO warning: still emitted on the fast path (observed live). The headlessSafetyWarnings refactor is sound — confirmed ApprovalMode.YOLO === 'yolo' in core, and the helper no longer imports core at runtime (guard + regex test cover it).

4. One non-blocking observation (LOW — optional follow-up)

isBootstrapServeRoute() matches the path exactly (req.path === '/health'), but Express non-strict routing still routes a trailing-slash GET /health/ to the health handler. Empirically on build A:

  • GET /health → 200 in 6 ms (full deferred sequence, fast path)
  • GET /health/ → 200 {"status":"ok"} but in 723 ms — classified as a non-bootstrap route, so it eagerly started the runtime and waited for the full mount before responding.

Same applies to /capabilities/ and /daemon/status/. The response is still correct, but the latency optimization is silently lost for the trailing-slash variant. Since the whole PR targets health-probe latency, consider normalizing the trailing slash in isBootstrapServeRoute. Not a merge blocker — canonical probes use /health.

Verdict

The PR does what it claims. The mechanism is correct and well-guarded (single runtimeStarting master guard against double-start; all three timers unref()'d and cleared on close; cancel-on-close path proven), the A/B confirms the first-/health improvement on a real daemon, and the new tests pass. Recommend merge, with the trailing-slash item as an optional follow-up.

🇨🇳 中文版(完整对应)

✅ 本地真实 daemon 验证(维护者)

在隔离 worktree 里基于 PR head(a55a21740,其 base main 已含 #5995)构建了真实打包的 dist/cli.js,并在 tmux 下驱动真实 qwen serve daemon。权威证据是 daemon 自身的调试日志 marker + 真实二进制上的 A/B 基准,而非客户端打印。

环境: macOS(Darwin 25.5)、Node v22.22.2 · 独立 npm ci worktree · 代码分割 bundle(serve fast path 落在独立 chunk)· loopback 绑定(--no-web,免 token)· QWEN_DEBUG_LOG_FILE=1

A/B 方法: 构建 A = PR 原样(deferRuntimeUntilFirstHealth: !parsed.open → 开)。构建 B = 仅改一行为 deferRuntimeUntilFirstHealth: false(PR 前基线),重新打包成不同 chunk 哈希。其余完全一致。

1. 首个 /health 延迟 —— 真实二进制 A/B(各 12 次,丢弃 2 次预热)

构建 listen → 首个 /health 200(隔离效应) spawn → 首个 /health 200 defer marker
A — defer 开(本 PR) 中位 3 ms(2–4) 中位 299 ms YES ✓
B — defer 关(基线) 中位 237 ms(233–261) 中位 529 ms NO ✓

→ 隔离指标 listen→/health 约 79×、减少 234 msspawn→/health 的 delta(−230 ms)相互印证(node 冷启动对 A/B 恒定)。基线下首个 /health 被 listen 后立即执行的 runtime graph mount(core 模块求值 + bridge 创建)阻塞;本 PR 把这部分推迟到 health 响应 flush 之后。方向与机制与 PR 主张一致("before" 的绝对值随 OS 不同——PR 引用的 Linux 机更大)。

2. 功能行为 —— 真实 daemon、tmux、daemon 调试日志 marker

场景 结果
health 触发启动 首个 /health → 200 {"status":"ok"}4 ms;日志:scheduling fallbackhealth served, scheduling start in 50mshealth timer fired, starting+51 msFAST_PATH_RUNTIME_START_AFTER_HEALTH_MS);fallback 触发 ✓
fallback(无探活) scheduling fallback start in 1000msfallback timer fired, starting+1001 msFAST_PATH_RUNTIME_START_FALLBACK_MS);无探活也启动 runtime ✓
首个 health 前关闭 SIGTERM → received SIGTERM, drainingdeferred runtime: cancelled, server closed before startup任何 runtime-start 定时器触发;优雅退出 ✓
首个 runtime 路由 GET /workspace/agents200(221 ms) 返回真实数据——非 bootstrap daemon_runtime_starting 503;它触发了 deferred 启动、等待 mount,由 runtime 服务;runtime 达到 READY(session reaper started + /acp WebSocket transport enabled)✓

3. 静态检查与测试

  • import 边界 guard npm run check:serve-fast-path-bundleServe fast-path bundle closure check passed(fast path 仍未把 core 拉进 pre-listen 闭包)。
  • 单元测试(vitest,真实构建):run-qwen-serve.test.ts(76)、fast-path.test.tsfast-path-open.test.tsheadlessSafetyWarnings.test.ts147 通过——含 3 个新增 deferred-runtime 用例。
  • Typecheckcli exit 0、core exit 0。
  • headless YOLO 警告:fast path 上仍正常输出(实测)。headlessSafetyWarnings 重构无误——已确认 core 中 ApprovalMode.YOLO === 'yolo',且 helper 运行时不再 import core(guard + 正则测试覆盖)。

4. 一个不阻塞合并的观察(LOW —— 可选后续)

isBootstrapServeRoute()精确匹配(req.path === '/health'),但 Express 非严格路由仍会把尾斜杠 GET /health/ 路由到 health handler。构建 A 上实测:

  • GET /health6 ms 返回 200(完整 deferred 序列,走 fast path)
  • GET /health/ → 200 {"status":"ok"} 但耗时 723 ms——被当作非 bootstrap 路由,于是提前启动 runtime 并等待整个 mount 完成才响应。

/capabilities//daemon/status/ 同理。响应仍正确,但尾斜杠变体悄悄丢掉了延迟优化。鉴于整个 PR 就是冲着 health 探活延迟去的,建议在 isBootstrapServeRoute 里归一化尾斜杠。非合并阻塞——规范探活用 /health

结论

PR 行为与主张一致。机制正确且守卫完备(runtimeStarting 单一主闸防重复启动;三个定时器均 unref() 且在 close 时清理;close-before-health 取消路径已证);A/B 在真实 daemon 上证实了首个 /health 的改善;新增测试全过。建议合并,尾斜杠一项作为可选后续。

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@doudouOUC
doudouOUC dismissed stale reviews from qwen-code-ci-bot and wenshao via e96599e June 30, 2026 07:13
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Comment thread packages/cli/src/serve/run-qwen-serve.ts
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No review findings. Downgraded from Approve to Comment: CI failing (Post Coverage Comment).

The deferred-runtime startup mechanism is correctly implemented with proper timer lifecycle management, idempotency guards, and comprehensive test coverage (147/147 tests pass). Deterministic analysis (tsc + eslint) is clean.

— qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@doudouOUC
doudouOUC added this pull request to the merge queue Jun 30, 2026

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I reviewed the latest deferred-startup flow and the added coverage around health/bootstrap handling, auth, CORS preflight, cancellation, and --open behavior; no blocking issues from my side.

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No critical or suggestion issues found beyond what prior reviews already covered. Downgraded from Approve to Comment: CI still running. The deferred-runtime startup mechanism is well-engineered with proper timer lifecycle management, idempotency guards, auth gating for deferred routes, CORS preflight bypass, and comprehensive test coverage (152 tests passing). Three low-confidence observations for human review: (1) deferred-mode blocks non-bootstrap requests for up to 120s without per-request timeout — clients preferring fast-fail get no 503 until the global startup timeout, (2) no test exercises concurrent health probe + runtime route arrival, (3) the health-trigger callback is registered on every 200 health response for the server's lifetime even after runtime has started.

— qwen3.7-max via Qwen Code /review

@yiliang114
yiliang114 removed this pull request from the merge queue due to a manual request Jun 30, 2026
@wenshao
wenshao added this pull request to the merge queue Jun 30, 2026
Merged via the queue into main with commit f37c64c Jun 30, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants