Server composition
The Python package is a set of service layers and replaceable responsibilities, not a standalone server process. A Cheetah deployment is assembled in three steps: choose a compatible implementation family, create the protocol roles that a process will serve, and integrate those roles into the host application's network and lifecycle.
The three decisions remain separate on purpose. A preset chooses how coordination works; factories choose which responsibilities a role receives; the host decides where and how the role runs.
The three server roles
| Role | Called by | Main responsibility |
|---|---|---|
| App | product code | authorize and address work, admit commands, correlate terminal outcomes, inspect delivery, query history and presence |
| WebSocket | a host WebSocket endpoint | authenticate client connections, negotiate the protocol, own live sockets, deliver commands, and accept client ACKs |
| REST | authenticated HTTP endpoints | ingest returned messages and state, fence and deduplicate them, retain accepted evidence, and notify waiters |
The role names describe responsibility, not process topology. A small application can put all three roles in one process. A larger deployment can run several instances of each role and coordinate them through Redis-backed implementations. Product code still calls the same App service in either shape.
The nodes are also not a chain of trusted in-process calls. A remote command normally leaves through the WebSocket role and returns through an independently authenticated REST edge. The shared registry, dispatcher, correlator, history, and response notifier preserve the relationship between those directions.
Keep one compatible component family
A ComponentSet groups the implementations intended to cooperate: authentication, presence, dispatch, correlation, history, response notification, deduplication, tracing, resource quota, node identity, and selected optional registries. The development, Redis, and production presets are known-compatible starting families.
Matching Python interfaces alone do not prove that an arbitrary mixture is coherent. Distributed implementations must also agree on deployment namespace, principal and routing rules, notification channels, retention behavior, lifecycle, and backing services. Separately created in-memory sets are separate worlds even if their configuration looks identical.
Presets and component sets lists the exact built-in families, their omissions, and the separate shared-tenancy composition path.
Give each role only what it consumes
Factories make dependencies visible instead of reaching into global state. The WebSocket role needs authentication and live-connection coordination. The REST role needs ingestion, deduplication, history, and response coordination. The App role needs presence, dispatch, correlation, history, and application policy services.
Response notification deserves particular attention: current REST and App construction requires an explicit notifier. They must receive compatible instances from the same component family so that an accepted response can wake the application process that is waiting for it.
Node roles and factories gives the current factory forms, required dependencies, configuration defaults, and a complete local composition.
Let the host own the running system
Node construction does not bind a port, mount an HTTP route, establish trusted forwarded headers, start Redis listeners, expose readiness, drain traffic, or close caller-owned Redis, storage, and tracing resources. Those are host responsibilities.
ComponentSet.start() and stop() manage the recognized background coordination hooks in a defined order. Startup compensates for a partial failure by stopping the hooks it already started; shutdown attempts every eligible hook before reporting failure. This is useful lifecycle support, but it is not a network supervisor or a complete readiness probe.
Lifecycle, readiness, and ownership defines that boundary and the failure behavior a host must design around.
For a task-oriented construction example, start with Compose the server. For application-facing methods after composition, continue to Application API.