fix(orchestration): treat ask as a long-poll so it survives the 30s socket idle wall#9351
fix(orchestration): treat ask as a long-poll so it survives the 30s socket idle wall#9351averydev wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughThe RPC runtime now classifies 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main/runtime/runtime-rpc.test.ts (1)
3566-3569: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReorder shutdown sequence and clean up the temporary directory.
It is safer to stop the server before closing the database to ensure that no in-flight requests or shutdown routines attempt to access a closed database connection, which could throw unhandled exceptions. Additionally, consider removing the temporary
userDataPathdirectory to avoid resource leaks across test runs.♻️ Proposed refactor
} finally { - db.close() await server.stop() + db.close() + rmSync(userDataPath, { recursive: true, force: true }) }
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 9184c62e-38c0-46b4-a212-5c5766e82e8f
📒 Files selected for processing (3)
src/cli/runtime/client.tssrc/main/runtime/runtime-rpc.test.tssrc/main/runtime/runtime-rpc.ts
…ocket idle wall
orchestration.ask blocks server-side until a reply lands or its timeout
(default 600s) elapses, holding the RPC open — but isLongPollRequest never
classified it as a long-poll. So the keepalive that resets the 30s
RUNTIME_RPC_SOCKET_IDLE_TIMEOUT_MS was never armed, and any ask left
unanswered for 30s died with a misleading runtime_unavailable ("The Orca
runtime closed the connection"), regardless of --timeout-ms. The same
omission left the handler's abort signal unwired (it is only passed for
long-polls), so the client-disconnect release path guarded by
signal?.aborted was dead code.
Add orchestration.ask to isLongPollRequest so it gets the keepalive, the
abort signal, and long-poll admission. The client already extends its
per-call socket timeout for ask (handlers/orchestration.ts passes
timeoutMs + 5s at the call site), so only the server-side classification
was missing.
c858168 to
1cd244d
Compare
Problem
orchestration.askblocks server-side until a reply lands or its timeout (default 600 s) elapses — it holds the RPC open exactly likecheck --wait(src/main/runtime/rpc/methods/orchestration.ts, the ask wait loop). ButisLongPollRequest(src/main/runtime/runtime-rpc.ts) only classifiedterminal.waitandorchestration.check --waitas long-polls.askfell through tofalse.Two consequences follow from that single omission:
startKeepalive()runs only for long-polls, soaskgets no{"_keepalive":true}frames. The socket's 30 s idle timer (RUNTIME_RPC_SOCKET_IDLE_TIMEOUT_MS,unix-socket-transport.ts) then firessocket.destroy(), and anyaskleft unanswered for 30 s dies with a misleadingruntime_unavailable— "The Orca runtime closed the connection before responding" — regardless of--timeout-ms.signal: longPoll ? context?.signal : undefined), so the ask handler'ssignal?.abortedguard (commented "if the asking client disconnects, release the waiter immediately") never runs.The
askhandler was written expecting long-poll treatment (600 s default block + signal-based disconnect handling); the §3.1 keepalive work was scoped to the reported symptom (check --wait) and never generalized toask.Reproduction (live, against the current build)
ask(before fix)runtime_unavailable— "runtime closed the connection"check --wait{count:0}(keepalives at 15/30/45 s)Fix
Add
orchestration.asktoisLongPollRequest— this arms the keepalive, wires the abort signal, and admits it under the long-poll cap.askblocks unconditionally, so no--wait-style param gate is needed. The keepalive machinery already exists;askwas simply never opted in.The client side already handles
askcorrectly: the CLIaskhandler passes an explicit per-call socket timeout (timeoutMs + 5s,src/cli/handlers/orchestration.ts), which is why the failure above was server-side at 30 s rather than a client-side cap. No client change is needed.Testing
emits keepalive frames while orchestration.ask blocks for a reply— drives a real socket, asserts ≥3 keepalive frames and anok:true/timedOut:trueterminal frame. Verified it fails without the fix (0 keepalives) and passes with it.runtime-rpc.test.ts— 48 passed.typecheck(node + cli projects) clean;oxlintclean.