Skip to content

fix(process-daemon): block subscriptions instead of polling - #59698

Merged
jlongster merged 1 commit into
devfrom
daemon-subscription-poll
Oct 27, 2026
Merged

jlongster merged 1 commit into
devfrom
daemon-subscription-poll

Conversation

@jlongster

@jlongster jlongster commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Ported from anomalyco/opencode-pty#28. Builds on #59694 (process-daemon-import, 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?

  • Part 1 of a stack that removes idle wakeups from the daemon (Idle daemon wakes the CPU ~100 times/s (10 ms sleep in the accept loop) opencode-pty#25). Stack: this PR → daemon-handler-spawn → daemon-control → daemon-poll-loop → daemon-windows-poll.
  • stream_subscription (packages/process-daemon/src/daemon/server.rs) waited in crossbeam_channel::select! with a default(Duration::from_millis(100)) => continue arm. That arm did nothing useful: it only looped back to check the shutdown flag again, so every attached subscription woke about 10 times a second while the terminal was idle. Remove it, so the handler now blocks until the disconnect monitor fires or a stream event arrives. The shutdown check at the top of the loop stays.
  • Shutdown does not rely on that poll to end subscriptions. After the accept loop exits, run cancels every handler connection before joining:
    • Unix: Cancellation::cancel calls shutdown(Both) on the socket. The DisconnectMonitor read then returns, disconnected() becomes ready, and the select exits.
    • Windows: Pipe::cancel sets the manual-reset cancelled event. Operation::wait waits on that event, so the monitor's pending read fails, and so does any new operation (Operation::new checks it first).
    • service.shutdown() stops every terminal actor, which drops the subscription event senders, so recv(attachment.events) ends with Err and the loop breaks.
    • A write that is blocked by backpressure fails with an error once its connection is cancelled.

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

How did you verify your code works?

  • New packages/process-daemon/tests/ownership.rs::shutdown_ends_an_idle_subscription: attaches an observer to an idle exec cat terminal, shuts down through the owner, and checks that the subscription stream reaches EOF within the client's 3s read timeout and that the daemon exits cleanly. On the original PR it ran 5 times in a row; all passed in about 0.08s each.
  • 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).

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-subscription-poll branch from a51d51c to d00c1a5 Compare October 27, 2026 20:07
@jlongster
jlongster merged commit f5cac12 into dev Oct 27, 2026
19 of 20 checks passed
@jlongster
jlongster deleted the daemon-subscription-poll branch October 27, 2026 22:20
alsuren pushed a commit to alsuren/opencode that referenced this pull request Oct 28, 2026
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