fix(client): abort-on-close watcher busy-spins while events are pending#101
Merged
Conversation
tanmaykm
reviewed
Jul 3, 2026
krynju
commented
Jul 3, 2026
The watcher added in #98 waited with `wait(stream_to); yield()` in a loop. `wait(::Channel)` returns as soon as data is *available*, so whenever an event sits in the channel before the consumer takes it, the loop spins hot — measured at 100% of a core in system time on a k8s watch stream. Poll `isopen` with a 250ms sleep instead; the watcher only exists to abort the read when the consumer walks away, so the added abort latency is irrelevant. Bumps to 0.2.6. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
0aa010a to
013624c
Compare
tanmaykm
approved these changes
Jul 3, 2026
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.
Repurposed — the original
readbytes!→readavailablechange is dropped: on a realHTTP.Stream,readbytes!returns per-chunk (verified empirically), so the original premise was wrong.Problem
The abort-on-close watcher introduced in #98:
wait(::Channel)returns as soon as data is available, not when the channel closes. So whenever an event has beenput!but not yet consumed — e.g. the consumer is busy converting the previous event — this loop spins hot. Measured live on a k8s watch stream: 100% of a core in system time (wchan=0, running thread, 400 stime ticks per 4s) for as long as any event sat in the buffered channel.Fix
Poll
isopenwith a 250ms sleep. The watcher exists only to abort the blocked read when the consumer closes the channel; 250ms of extra abort latency is irrelevant, and the loop now costs nothing while idle.Found while diagnosing deaf k8s watches in JuliaHub's JobLoops (root cause was in Kuber.jl — see JuliaComputing/Kuber.jl#67 — but this spin was compounding it by starving the same thread pool).
Bumps to 0.2.6.
🤖 Generated with Claude Code