corvix.web.sse

Server-Sent Events: push snapshot updates instead of client-side polling.

The server polls storage on a short interval and pushes a snapshot event only when the serialized payload actually changes, so idle connections cost a periodic comparison (plus an occasional keep-alive) rather than a full response on every tick. Browsers reconnect automatically via EventSource, and the frontend falls back to interval polling when SSE is unavailable.

A short-lived, process-wide cache of the serialized body (keyed by dashboard) collapses the storage reads of concurrent connections watching the same dashboard into roughly one read per poll interval, instead of one read per connection per tick.

Attributes

Functions

_sse_poll_interval(→ float)

Return the server-side SSE poll interval in seconds.

_snapshot_event_body(→ str)

Build the snapshot payload and serialize it to a compact JSON string.

_cached_snapshot_event_body(→ str)

Return the snapshot body for dashboard, reusing a build newer than ttl.

_snapshot_error_payload(→ str)

Serialize an SSE snapshot-error payload for error.

_snapshot_event_generator(...)

Yield SSE messages for dashboard, pushing only on change.

events(→ litestar.response.ServerSentEvent)

Stream dashboard snapshots as Server-Sent Events.

Module Contents

corvix.web.sse.logger[source][source]
corvix.web.sse._SSE_DEFAULT_POLL_INTERVAL_SECONDS = 3.0[source][source]
corvix.web.sse._SSE_KEEPALIVE_SECONDS = 20.0[source][source]
corvix.web.sse._sse_poll_interval() float[source][source]

Return the server-side SSE poll interval in seconds.

Read from CORVIX_SSE_POLL_INTERVAL_SECONDS; falls back to the default when unset, non-numeric, or non-positive.

corvix.web.sse._snapshot_event_body(dashboard: str | None) str[source][source]

Build the snapshot payload and serialize it to a compact JSON string.

Uses msgspec (the encoder Litestar uses for the equivalent HTTP route) so the SSE body and the GET /api/v1/snapshot response share one serialization path and stay byte-for-byte consistent.

corvix.web.sse._snapshot_body_cache: dict[str | None, tuple[float, str]][source][source]
corvix.web.sse._snapshot_body_cache_lock[source][source]
corvix.web.sse._cached_snapshot_event_body(dashboard: str | None, ttl: float) str[source][source]

Return the snapshot body for dashboard, reusing a build newer than ttl.

Within a ttl-second window (one poll interval) concurrent SSE connections watching the same dashboard share a single storage read and serialization. A strict age < ttl comparison means a lone connection, whose ticks are spaced one interval apart, still rebuilds every tick — so the cache adds no latency in the common single-client case.

corvix.web.sse._snapshot_error_payload(error: Exception) str[source][source]

Serialize an SSE snapshot-error payload for error.

HTTPException carries a client-safe detail and status code; any other exception is reported generically (its message is not leaked to the client).

async corvix.web.sse._snapshot_event_generator(dashboard: str | None) collections.abc.AsyncIterator[litestar.response.ServerSentEventMessage][source][source]

Yield SSE messages for dashboard, pushing only on change.

Emits a snapshot event whenever the serialized payload differs from the last one sent, a snapshot-error event when the payload cannot be produced, and a comment-only keep-alive when nothing has changed for a while (so proxies do not drop an idle connection). The blocking storage read runs in a worker thread to avoid stalling the event loop.

Any error building the snapshot is reported to the client and the stream keeps running, recovering on a later tick; this avoids tearing down the connection (and triggering a client reconnection storm) on a transient storage or serialization failure.

async corvix.web.sse.events(dashboard: str | None = None) litestar.response.ServerSentEvent[source][source]

Stream dashboard snapshots as Server-Sent Events.

Replaces fixed-interval client polling: the connection stays open and the server pushes a snapshot event only when the data changes, cutting both latency and per-cycle overhead when nothing has happened.