Fix session init hang when start runs in an uninterruptible region (0.4.1) #50
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
iterative-works/claude-code-query!50
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/session-init-interruptible"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Downstream (the
proceduresdashboard, PROC-589), opening a worker session hung forever: the bootstrap turn spawned the CLI but never produced an init message or any terminal frame.Root cause
SessionProcess.readInitMessagewaits for the CLI's init message with:ZIO.timeoutcompletes by interrupting the losingtakewhen the sleep wins — so it can only fire if thetakeis interruptible. If a caller runssession/startinside an uninterruptible region, thetakeis uninterruptible, the interruption blocks, and the timeout never fires.That is easy to hit in practice: a forked fiber inherits its parent's interrupt status, and request handlers (e.g. tapir-netty) run uninterruptibly, so
…forkDaemonbackground work is uninterruptible. The worker CLI's init is legitimately slow when it does an MCP handshake before emitting its firststream-jsonline — exactly the case the 1s timeout exists to tolerate (proceed with apendingsession id). With the timeout dead, "slow init" becomes an infinite hang.The bare-CLI / mock suites never caught this because they run the wait in an interruptible context (
ZIO.scopedin tests, fast init with no MCP).Fix
Force the bounded init-wait
interruptibleso the timeout always fires regardless of the caller's ambient interrupt status:A self-contained startup timeout must not silently become unbounded based on how the caller scopes interruption.
Tests
SessionTest): drivesreadInitMessageunderZIO.uninterruptibleand observes completion from an interruptible fiber — fails by observer-timeout without the fix, passes (≈1s) with it.readInitMessageis nowprivate[claude]so the unit test can drive it directly.zio/itest/SessionE2ETest): exercises a long-lived ZIOSessionagainst the real CLI (single turn, multi-turn context, session-id stability) — the stdin-streaming path the existing ZIO suites only drove via a bash mock../mill zio.test(10/10) and./mill zio.itest.compilegreen.Release
Bumps
publishVersionto 0.4.1 (patch). See the release steps in the PR discussion /publish.yml(tagv0.4.1→ Sonatype Central).Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
🤖 Generated with Claude Code