fix(runtime): settle Pi RPC shutdown on close when the spawn itself failed - #219
Merged
eddiearc merged 2 commits intoSep 13, 2026
Merged
Conversation
…ailed Node emits "error" + "close" (never "exit") when a spawn fails, so beginShutdown() waited out both shutdownGraceMs timers — and with nothing else keeping the loop alive, close() never settled at all. Treat "close" as a terminal event alongside "exit" so failed spawns settle promptly, keeping the SIGTERM/SIGKILL escalation for stubborn children unchanged. Co-Authored-By: Claude Code <noreply@anthropic.com>
Contributor
Author
|
补充一条真实场景的耗时证据:在 0.5.7 的真实 setup 里,pi 探测因 spawn 失败(cwd 缺失)而失败时,调用方等了 4020ms 才拿到错误——正是 beginShutdown 等不到 |
This was referenced Sep 13, 2026
eddiearc
approved these changes
Sep 13, 2026
eddiearc
left a comment
Owner
There was a problem hiding this comment.
MERGE-WITH-NITS(Fable 5.1 审合)
Node 失败 spawn 只有 error+close、没有 exit;shutdown 只等 exit 会拖满 ~4s grace。把 close 也当终态是对症修复,FailedSpawnProcess 用例到位。SIGTERM→SIGKILL 路径未动。
请先于 #224 合(同改 pi-rpc-client + 测末尾)。缺 package.json bump,跟整批 release 策略一起定即可。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
PiRpcClient.beginShutdown()waits on the child'sexitevent. Node emitserror+closeand neverexitwhen the spawn itself fails, so a failed pi spawn madeclose()take ~4 seconds (twoshutdownGraceMstimers, sincekill()on a failed spawn returnsfalse) — and with nothing else keeping the event loop alive, the promise never settled at all.this.exitedwas also only set in theexithandler, so the existing fast-path (if (this.exited) return Promise.resolve()) could not trigger.Change
src/runtime/pi-rpc-client.ts: treatcloseas a terminal event alongsideexit— both in the constructor's termination handler (this.exited+ fail-closed) and inbeginShutdown()(finishon either event). Normalexit→closesequences and the SIGTERM→SIGKILL escalation for stubborn children are unchanged.src/runtime/runtime-adapters.ts: the localProcessLikechild-process contract gains the matchingcloseoverload.test/unit/runtime/pi-rpc-client.test.mjs:FailedSpawnProcessdouble (emitserror+close, noexit,kill()returnsfalse) asserting shutdown settles in under a second instead of waiting out the grace timers.Validation
t=3ms request rejected: Pi RPC process failed: spawn <path> ENOENT→t=9ms child close code=-2→t=4003ms close resolved. After the change, the catalog call fails in 50ms with the same error.bun run build✅bun run typecheck✅bun run licenses:check✅ ·bun run publication:check:tree✅bun test test/unit/runtime/pi-rpc-client.test.mjs test/unit/runtime/pi-model-catalog.test.mjs→ 21 pass / 0 failbun test test/unit/runtime/→ 232 pass / 0 failbun run test:unit→ 896 pass / 1 skip / 1 fail. The remaining failure,three-Agent live acceptance is opt-in, hermetic by default, and fixture-verifiable, reproduces on unmodifiedmainin this environment and is unrelated to this change; a one-offreal dashboard … SIGINTtimeout in an earlier run did not recur and passes standalone in ~320 ms.Fixes #218
🤖 Generated with Claude Code