docs: README streaming/SSE sections, ROADMAP v0.3 done, crud SSE ticker (v0.3 chunk 4)
README: write_timeout in the Config sample, read/write timeout-split semantics spelled out, new Streaming Responses and Server-Sent Events sections (producer contract, 1.0 fallback, heartbeat liveness), roadmap summary bumped. ROADMAP: v0.3 marked done with the as-landed decisions (pull shape per the user's fork answer; Q3 timeout split as proposed) and verified exit criteria. crud example: GET /ticker SSE route — one event/second, producer exits on SseClosed or the example's shutdown flag (so an open ticker doesn't block AllDone past the drain).
This commit is contained in:
+33
-12
@@ -119,22 +119,43 @@ panicking listener restarts under load without dropped accepts (test each).
|
||||
|
||||
---
|
||||
|
||||
## v0.3 — Streaming bodies + SSE
|
||||
## v0.3 — Streaming bodies + SSE ✅ (landed 2026-06, chunks 1-3)
|
||||
|
||||
The slipped v1 goal, and the WebSocket prerequisite (an upgraded connection
|
||||
is "a response that never ends").
|
||||
|
||||
1. `RespBody::Stream(...)` — handler hands back a writer callback or a
|
||||
`Receiver<Vec<u8>>`; conn actor switches to chunked transfer-encoding
|
||||
(HTTP/1.1) and pumps until the stream closes. Keep-alive after a
|
||||
completed chunked response.
|
||||
2. Chunked **request** bodies (`parser.rs` currently returns 411) — same
|
||||
cycle, the codec knowledge is fresh.
|
||||
3. SSE sugar: `Conn::sse()` → an `EventSender` (`.send(event, data)`),
|
||||
sets `content-type: text/event-stream`, disables buffering, heartbeats
|
||||
via comment lines on a timer. An SSE conn is just a Stream body with
|
||||
the per-read deadline disabled (or set to the heartbeat interval) —
|
||||
liveness comes from the keep-alive ping, not `request_timeout`.
|
||||
1. `RespBody::Stream(StreamBody)` ✅ — **decided: pull** (user call at the
|
||||
v0.3 design fork): the handler hands back a `smarm::Receiver<Vec<u8>>`
|
||||
and the producer is an actor the handler spawned; the conn actor pumps
|
||||
(`pump_stream`) and keeps sole ownership of the socket and write
|
||||
deadlines. The recv() park between chunks is stoppable by the draining
|
||||
registry, so infinite streams die at the drain deadline with no
|
||||
polling. HTTP/1.1: chunked TE, keep-alive after the terminator;
|
||||
HTTP/1.0: raw bytes, forced close, EOF-delimited. End of stream =
|
||||
every Sender dropped = 0-chunk. Timeout split (handoff Q3, as
|
||||
proposed): `request_timeout` covers the READ phase only; new
|
||||
`Config.write_timeout` (default 30s) bounds every response write —
|
||||
fresh budget per streamed chunk, and the fixed-body + error-response
|
||||
writes went deadline-bounded too (write-side slowloris closed).
|
||||
2. Chunked **request** bodies ✅ — `read_chunked_body` decodes
|
||||
incrementally on the request deadline; extensions ignored, trailers
|
||||
consumed + discarded, decoded size capped at max_body_bytes (413),
|
||||
size-line/trailer spam capped (400). CL + TE: chunked, or chunked on
|
||||
HTTP/1.0, rejected 400 at parse (smuggling ambiguity). Keep-alive
|
||||
drain accounts RAW framing length, so pipelined requests behind a
|
||||
chunked body land exactly.
|
||||
3. SSE sugar ✅ — `Conn::sse()` / `sse_with_heartbeat` → `EventSender`
|
||||
(`send(event, data)` / `data` / `comment`, Clone, `Err(SseClosed)`
|
||||
once the stream is gone). Heartbeat lives in the pump as leaned: with
|
||||
`StreamBody.heartbeat` set, the chunk wait is `recv_timeout(interval)`
|
||||
and expiry writes a `: keep-alive` comment chunk. Liveness from the
|
||||
ping (dead client = heartbeat write stalls past write_timeout), not
|
||||
from any request clock.
|
||||
|
||||
**Exit criteria (verified):** chunked round-trips both directions with
|
||||
keep-alive and pipelining intact; an infinite SSE stream heartbeats while
|
||||
silent, is killed by write_timeout when the client stops reading, and is
|
||||
force-stopped at the drain deadline on shutdown; full suite green.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user