Skip to content

fix: 收到 result 后立即跳出消息循环,避免 idle timeout 误报#258

Merged
lishuceo merged 3 commits into
mainfrom
fix/result-idle-timeout
Jun 8, 2026
Merged

fix: 收到 result 后立即跳出消息循环,避免 idle timeout 误报#258
lishuceo merged 3 commits into
mainfrom
fix/result-idle-timeout

Conversation

@lishuceo

@lishuceo lishuceo commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • 收到 SDK result 消息后用 labeled break 立即跳出 for await 循环
  • 调用 q.close() 确保子进程不泄漏

问题

urhox-bench · feat/p0-4-opus-baseline 频繁报 Query idle timeout after 600s with no activity

根因:SDK 返回 result 后,如果有 background task 仍在运行,for-await 循环不会自然结束。原来的 break 只跳出了 switch,循环继续等待下一条消息,idle timer 持续倒计时直到触发超时——但实际查询已经成功完成。

修复

  • breakbreak messageLoop(labeled break 跳出整个 for-await)
  • 循环后 q.close() 确保即使有 background task,子进程也能干净退出

Test plan

  • urhox-bench 长时间执行场景不再误报 idle timeout
  • 正常短查询行为不受影响
  • 无子进程泄漏(ps 确认无残留 claude 进程)

🤖 Generated with Claude Code

问题:SDK 返回 result 消息后,如果有 background task 仍在运行,
for-await 循环不会结束,导致 idle timer 继续倒计时最终触发超时。
实际查询已经成功完成,不应该报超时。

修复:用 labeled break 在收到 result 后立即跳出循环,
并调用 q.close() 确保子进程不泄漏。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Claude Code is working…

I'll analyze this and get back to you.

View job run

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Claude Code is working…

I'll analyze this and get back to you.

View job run

问题:urhox-bench 的 .claude/settings.local.json 包含完整的 bash 命令
白名单(git/npm/npx/gh 等),但 SDK 只传了 ['user', 'project'],
'local' 未包含,导致这些权限不生效。SDK 弹窗请求授权时飞书 bot
无法交互,报 "Stream closed"。

修复:settingSources 加入 'local',优先级:user < project < local。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Claude finished @lishuceo's task in 4m 52s —— View job


Code Review — PR #258

Verdict: ✅ Approved — correct, minimal fix that matches SDK semantics.

Analysis

The root-cause diagnosis is accurate. query() returns an AsyncGenerator whose for await loop does not terminate while background tasks keep the underlying subprocess alive — so the idle timer kept counting after a successful result, producing false idle timeout errors.

The fix is idiomatic per the SDK type definitions:

  • break messageLoop (executor.ts:1128) — result is the SDK's terminal protocol message, so breaking the loop immediately is correct. The previous bare break only exited the switch, leaving the loop blocked on the next (never-arriving) message.
  • q.close() (executor.ts:1140) — exactly the right call. The SDK docs state close() "forcefully ends the query, cleaning up all resources including pending requests, MCP transports, and the CLI subprocess." This is what reaps the background-task subprocess. It's also already used consistently in killSession/killSessionsForChat/killAll, and the idempotency claim in the comment holds.
  • settingSources: [..., 'local'] (executor.ts:949) — 'local' is a valid SettingSource ('user' | 'project' | 'local'), so this correctly loads .claude/settings.local.json. ✅

Minor observations (non-blocking)

  • 🟡 q.close() is inside the try block (confidence ~50, below report threshold but noting). If close() ever threw, control would jump to the catch at executor.ts:1141 and the already-captured resultMessage would be discarded — reporting a successful query as a failure. close() returns void and is "forceful," so this is unlikely, but moving it after the loop's clearTimeout (or wrapping in try/catch) would be more defensive.
  • 🟡 No regression test. Per CLAUDE.md ("Bug fix 需附带回归测试"), a bug fix should ship a regression test. executor.ts has no existing test file and is hard to unit-test due to subprocess streaming, so this is understandable — but a mock-generator test asserting the loop exits on result and close() is invoked would lock in the fix.

Summary

  • Read full executor.ts context
  • Verified SDK Query.close() / SettingSource semantics
  • Confirmed labeled-break correctness
  • No prior inline comments to resolve

Solid fix. The two notes above are optional hardening, not blockers.

@lishuceo lishuceo merged commit d9afbce into main Jun 8, 2026
4 checks passed
@lishuceo lishuceo deleted the fix/result-idle-timeout branch June 8, 2026 09:27
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.

1 participant