Server¶
The Litestar orchestrator that hosts a Golit app. See Running your app, Server-push updates, and Deployment & scaling.
create_app¶
create_app
¶
create_app(
app: App,
*,
pubsub: PubSub | None = None,
session_store: SessionStore | None = None,
middleware: Sequence[Any] | None = None,
guards: Sequence[Any] | None = None,
dependencies: Mapping[str, Any] | None = None,
on_app_init: Sequence[Any] | None = None,
on_startup: list[LifecycleHook] | None = None,
on_shutdown: list[LifecycleHook] | None = None,
) -> Litestar
Wire a Golit blueprint into a runnable Litestar application.
pubsub overrides the SSE fan-out backend and session_store the durable
session-state backend; by default each is chosen from the environment (Redis
when GOLIT_REDIS_URL is set, in-memory otherwise). Extra on_startup
hooks can launch background tasks (e.g. a ticker that publishes invalidations
to app.state.pubsub for the SSE channel).
middleware, guards, dependencies and on_app_init are forwarded
verbatim to the Litestar constructor — Litestar only accepts these at build
time, so this is how you bring your own auth, rate limiting, or per-route
authorization (Golit ships none). See Security & hardening in the docs.
Source code in python/golit/server/factory.py
pubsub_from_env
¶
pubsub_from_env() -> PubSub
Pick the fan-out backend from the environment: Redis when
GOLIT_REDIS_URL is set (multi-worker), in-memory otherwise (single-node).
Redis is an optional dependency, imported only when actually selected.
Source code in python/golit/server/factory.py
Invalidation & pub/sub¶
The SSE fan-out channel. Invalidation is the unit published when a node goes dirty server-side; PubSub is the protocol both backends implement.
Invalidation
dataclass
¶
PubSub
¶
Bases: Protocol
InMemoryPubSub
¶
Process-local pub/sub: every listener receives every invalidation, mirroring Redis pub/sub fan-out semantics on a single node.
Source code in python/golit/server/pubsub.py
publish
async
¶
publish(inv: Invalidation) -> None
listen
async
¶
listen() -> AsyncIterator[Invalidation]
RedisPubSub
¶
RedisPubSub(
url: str = DEFAULT_URL,
*,
channel: str = DEFAULT_CHANNEL,
client: Redis | None = None,
)
Fan invalidations out across workers via a Redis pub/sub channel.
A drop-in for :class:InMemoryPubSub. client may be injected (e.g. a
fakeredis instance in tests); otherwise a client is built lazily from
url on first use, so importing this module never requires a live Redis.
Source code in python/golit/server/redis_pubsub.py
publish
async
¶
publish(inv: Invalidation) -> None
listen
async
¶
listen() -> AsyncIterator[Invalidation]
Source code in python/golit/server/redis_pubsub.py
aclose
async
¶
Release the shared client (called from the server shutdown hook).
Sessions & SSE¶
SessionManager
¶
SessionManager(
app: App,
*,
store: SessionStore | None = None,
max_sessions: int = DEFAULT_MAX_SESSIONS,
ttl_seconds: float = DEFAULT_TTL_SECONDS,
)
A bounded, thread-safe map of session id → live :class:Session, backed by
a durable :class:SessionStore for the input state.
Idle sessions expire after ttl_seconds and the least-recently-used is shed
once the live count would exceed max_sessions (set either to 0 to
disable). store defaults to the no-op in-memory store (single-node).
Source code in python/golit/server/session.py
get_or_create
¶
get_or_create(sid: str | None) -> tuple[str, Session, bool]
Resolve a session by cookie id. Returns (sid, session, created).
created is True only for a brand-new session, signalling the caller
to set the cookie and run the initial render. A session reconstructed
from the durable store is returned created=False and already rendered
(its inputs replayed) — the client already holds the cookie.
Source code in python/golit/server/session.py
get
¶
get(sid: str | None) -> Session | None
Fast, local-only lookup (no reconstruction) — used by the SSE dispatch loop, which must not block on store I/O or a heavy rebuild.
Source code in python/golit/server/session.py
prepare
¶
prepare(
cookie_sid: str | None,
) -> tuple[str, Session, bool]
Resolve a render-ready session for a request: reuse/reconstruct/create, running the initial render for a brand-new one.
Source code in python/golit/server/session.py
prepare_and_update
¶
prepare_and_update(
cookie_sid: str | None, input_id: str, raw: object
) -> tuple[str, Session, bool, dict[str, str]]
Resolve the session, commit the input change, persist it for other
workers, and return the changed fragments. Raises KeyError for an
unknown input (propagated to a 404).
Source code in python/golit/server/session.py
lock_for
¶
The per-session lock serializing that session's requests. A missing id (brand-new client, no cookie yet) gets a fresh, uncontended lock.
Source code in python/golit/server/session.py
SSEManager
¶
SSEManager(sessions: SessionManager, pubsub: PubSub)
Source code in python/golit/server/sse.py
connect
¶
disconnect
¶
dispatch
async
¶
dispatch(inv: Invalidation) -> None
Recompute the affected session(s) and enqueue the changed fragments.
Each recompute runs under that session's per-session lock — the same
lock the request path holds (see :meth:SessionManager.lock_for) — so a
server-pushed refresh never interleaves with a client POST mutating the
same in-place kernel graph + registry. The recompute is CPU-bound (Polars +
render), so it's offloaded to a worker thread to keep the event loop
responsive while the lock is held across the await.
Source code in python/golit/server/sse.py
run
async
¶
stream
async
¶
stream(
sid: str,
*,
ping_interval: float = DEFAULT_PING_INTERVAL,
) -> AsyncIterator[ServerSentEventMessage]
Source code in python/golit/server/sse.py
Chat¶
The WebSocket chat channel. See WebSocket chat.
ChatMessage
dataclass
¶
MessageContext
¶
MessageContext(
hub: ChatHub, channel: str, session: str | None
)
Handed to an @app.on_message handler so it can respond to a message.
Source code in python/golit/server/chat.py
ChatHub
¶
Tracks open connections per channel, keeps a short history, and fans messages out. Holds no sockets — only outbound queues — so it is trivially testable and the transport (the WebSocket route) stays separate.
Source code in python/golit/server/chat.py
join
¶
leave
¶
history
¶
history(channel: str) -> list[ChatMessage]
broadcast
async
¶
broadcast(channel: str, msg: ChatMessage) -> None
Store msg in history and enqueue it for every connection on the channel.
Source code in python/golit/server/chat.py
reply
async
¶
reply(
channel: str, session: str | None, msg: ChatMessage
) -> None
Enqueue msg only for connections owned by session (no history).
Source code in python/golit/server/chat.py
handle_incoming
async
¶
Process a raw inbound payload from a client (the form fields HTMX sent).
With no handler for the channel, the message relays to the room. With a
handler, it owns the message via :class:MessageContext.
Source code in python/golit/server/chat.py
Kernel version¶
golit.kernel_version() returns the version string of the compiled Rust kernel (golit._golit). It's a plain function with no arguments: