Merge branch 'wt/review-002-ws13-idle-progress'
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-08-27
|
||||
last_updated: 2026-08-30
|
||||
---
|
||||
|
||||
# WebSocket — the Browser Bidirectional Path (Channels over WS)
|
||||
@@ -176,6 +176,49 @@ The adapter is shared with the `from_wss` consumer path
|
||||
([ADR-070](decisions/070-from-wss-consumer-adapter.md)) — one
|
||||
implementation, both directions.
|
||||
|
||||
#### Idle-read timeout: progress semantics + the no-keepalive decision (WS-01, WS-13)
|
||||
|
||||
The WS pumps carry an **idle-read eviction knob**
|
||||
(`HttpAdapter::with_ws_idle_timeout`, default
|
||||
`DEFAULT_WS_IDLE_TIMEOUT` = 60 s, disable with `None`). Its semantics,
|
||||
decided in review-002 (WS-13), are **progress-based, deliberately
|
||||
strict**:
|
||||
|
||||
- The deadline resets on **demux progress** — bytes actually forwarded
|
||||
into the byte stream that *complete* an inbound chunk (a full
|
||||
8-byte header + its declared payload). WS message arrival resets
|
||||
nothing.
|
||||
- Therefore the dribble stall (declare a chunk, deliver its payload a
|
||||
byte per message) hits the deadline and is evicted with a `1001`
|
||||
(GoingAway) close — even though messages keep arriving — while a
|
||||
peer delivering complete chunks, however slowly per message, re-arms
|
||||
the window with each chunk and survives.
|
||||
- **There is no WS ping/pong keepalive, on purpose.** A keepalive
|
||||
rescues app-silence only by re-arming the deadline — and a pong is
|
||||
indistinguishable from the dribble's almost-invisible arrivals, so
|
||||
adding one would reopen the stall it exists to seal. The recorded
|
||||
decision (module doc of `src/websocket/byte_adapter.rs`, option (b)
|
||||
of the two WS-13 alternatives): **60 s of no chunk progress is an
|
||||
intentional eviction line, even for a silent subscription.**
|
||||
- A deployment running long-lived silent-but-alive sessions (quiet
|
||||
subscriptions that outlast the window) disables the knob with
|
||||
`with_ws_idle_timeout(None)` and leans on the remaining levers:
|
||||
the session registry's forced-eviction
|
||||
([`WsSessions::abort`](#connection-local-overlay)), the
|
||||
inbound caps (WS-06), and the write-side caps (WS-04/05/06). This is
|
||||
the same deployment posture as `from_wss`'s drop monitor
|
||||
([ADR-070](decisions/070-from-wss-consumer-adapter.md)): the idle
|
||||
knob bounds *demux parking*, not app liveness.
|
||||
- Layered note (the WS-13/FWD-15 interaction recorded here): the
|
||||
*HTTP* SSE path (`/subscribe`) sends server-side keep-alive comment
|
||||
frames every 15 s — see
|
||||
[http-server.md](http-server.md)) — because its idle enemy is
|
||||
LB/proxy timeouts, and its keep-alive does not reset any
|
||||
progress deadline, it cannot reopen the WS-13 hole. The two live at
|
||||
different layers: SSE keep-alive fights transport fires; the WS idle
|
||||
knob bounds demux parking. Both documented in the same pass per
|
||||
review-002 Unit-2 sequencing.
|
||||
|
||||
### Dispatch: channel 0 = the shared `Dispatcher`, unchanged
|
||||
|
||||
Channel 0's session is the alknet design's native session, verbatim:
|
||||
|
||||
Reference in New Issue
Block a user