Skip to content

fix(process-daemon): survive thread spawn failures - #59699

Closed
jlongster wants to merge 1 commit into
devfrom
daemon-handler-spawn
Closed

jlongster wants to merge 1 commit into
devfrom
daemon-handler-spawn

Conversation

@jlongster

@jlongster jlongster commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Ported from anomalyco/opencode-pty#29. Part 2 of the stack for anomalyco/opencode-pty#25. Part 1 (#59698) is merged.

Issue for this PR

Related to anomalyco/opencode-pty#25

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

  • thread::spawn panics when the OS can't create a thread. In the daemon that panic skipped orderly shutdown and cleanup, or failed in confusing ways. I found this while planning the readiness-driven loop. All daemon threads now start through thread::Builder, are named opencode-pty-*, and handle spawn failure explicitly:
    • Connection handler: if the spawn fails, that connection is dropped (the peer sees EOF) and the daemon keeps serving.
    • Shutdown watchdog: if the spawn fails, the daemon logs it and continues orderly shutdown without the backstop.
    • Subscription disconnect monitor: if the spawn fails, the existing io error is returned.
    • Stale-runtime sweeper: optional. If the spawn fails, the daemon logs it and continues.
  • Terminal startup in packages/process-daemon/src/service.rs now cleans up fully after any partial failure. It kills and reaps the child, and joins any threads that already started through the existing TerminalHandle::shutdown path. The child is handed to the waiter only once the waiter is running.
  • Threads now start in the order reader → waiter → actor → writer. If actor init fails on Windows, the pseudoconsole closes through the normal close path while the reader drains it. This fixes a pre-existing case where ClosePseudoConsole could hang on older Windows.
  • Known remaining edge: if the reader thread itself fails to spawn right after the child starts, ClosePseudoConsole can still block on older Windows when the child has already written more than the pipe buffer holds. Fixing that means starting the reader before spawning the child, which is deliberately out of scope here.

The commit applied to the monorepo unchanged (identical patch ID to the opencode-pty commit).

How did you verify your code works?

  • No tests added: there's no way to force thread creation to fail without process-wide limits or mocks.
  • Port validation (macOS arm64, Rust 1.90.0, in packages/process-daemon): cargo fmt --check, cargo clippy --locked --all-targets --all-features -- -D warnings, and cargo test --locked --lib (40 passed) pass.
  • On the stack tip (daemon-windows-poll) the full macOS CI test selection and Windows/Linux cross clippy also pass.
  • Original PR: the macOS CI test selection passed: cargo test --locked --lib --test service --test runtime --test ownership --test rows --test ghostty-effects (lib 40, ghostty-effects 5, ownership 8, rows 1, runtime 8 + 1 ignored, service 9). Native Windows relies on CI.

Screenshots / recordings

N/A, internal daemon change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@jlongster
jlongster force-pushed the daemon-handler-spawn branch from 6b21f80 to 6fac8bd Compare October 27, 2026 22:21
@jlongster

Copy link
Copy Markdown
Contributor Author

Closing: we're accepting that thread::spawn panics on thread-creation failure; this was too much change for that edge case. #59700 now builds directly on dev.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant