Repository navigation
docs: keep the event-bus loop short; a held event delays noticing a lost server #316
Description
What
The streaming guide's "A live bus that reconnects" section (added by #315 for #176) should tell consumers to keep the await foreach loop over client.Events.SubscribeAsync short. Long work belongs elsewhere: hand each event to a Channel<IEvent> (or another queue) and return to the loop at once. The guide should include a short sample of that hand-off.
Why
The SDK's bus is pull-based. The next bytes are read only when the consumer asks for the next event. While the consumer holds an event, its 45 s idle window is stopped, because the consumer's own time is not the server's silence (client-runtime.md, Server-sent events).
The consequence is that a server lost while the consumer holds an event is noticed only when the consumer asks again:
- Clean loss (process ended, connection reset): the next read fails at once, and the bus reconnects one second later. Detection is late by the time the event was held.
- Half-open connection (no reset ever arrives): the idle window runs its full 45 s from the moment the consumer asks again.
Upstream's first-party client reads in the background, so it notices the loss and reconnects while its consumer is busy. The gap of missed events is therefore shorter there. Its consumers are UI handlers that never hold an event, so the question doesn't arise for them.
A consumer that keeps the loop short gets the same timing as upstream, with no change to the SDK. The guide should say so, and say why: a repeated EventServerConnected still means events were missed, and the shorter the loop, the smaller that gap.
Considered and not proposed
The SDK could read the bus in the background itself, through an internal buffer. That costs:
- A new decision on the buffer. Unbounded, a slow consumer grows the client's memory. Bounded, the SDK has to choose what to do when it is full, which would be a new behaviour that upstream doesn't have.
- The natural back-pressure. Today a slow consumer fills TCP, and the server fails the stream with its own slow-consumer failure frame, which the bus reconnects from.
- A background task per stream, with failure routing and disposal ordering on top.
The maintainer (2026-10-15) chose to document the trade-off rather than change the model. An opt-in buffered subscription can be revisited if consumers ask for it.
Acceptance
docs/guide/streaming.md, in "A live bus that reconnects", gets:- one paragraph on keeping the loop short and what holding an event delays;
- a minimal
Channelhand-off sample, which compiles against the current public API.
docs/architecture/client-runtime.mdneeds no change. It already states that the window stops while an event is held.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsQueue
Activity