Lifecycle, readiness, and ownership
Creating a component set and node objects proves only that construction succeeded. A running deployment also needs coordination listeners, mounted network edges, backing services, product dependencies, readiness rules, traffic draining, and final resource cleanup.
Component-set startup order
await components.start() invokes recognized lifecycle hooks in this order:
- initialize a lifecycle-capable context registry;
- start the command-dispatch listener;
- start the RPC-correlator listener;
- start the response-notifier listener;
- start the connection-registry sweep.
The context step comes first because the Redis topology registry must establish whether its atomic mutation facility is available before dependent listeners accept work. In-memory components usually have no lifecycle hooks, so the same host pattern becomes a no-op for a development set.
If a step fails, ComponentSet.start() stops only the hooks that completed, in reverse start order, before re-raising the primary failure. Cleanup failures are logged and attached as secondary notes where the Python runtime supports them. Cancellation is also propagated only after completed starts have been unwound.
This compensation prevents the known listeners from being silently left behind. It does not roll back external work performed by custom hooks, start a network server, or prove that a separate process is ready.
Shutdown order and failure behavior
await components.stop() attempts these eligible hooks:
- stop the registry sweep;
- stop the RPC correlator;
- stop the response notifier;
- stop the dispatcher;
- stop a lifecycle-capable context registry.
Every eligible stop is attempted even if an earlier one fails. The first ordinary failure is reported after cleanup; process-control exceptions and cancellation take precedence while other failures remain observable.
The current stop order is an explicit implementation contract, but it does not drain App, REST, or WebSocket calls. Stop accepting new traffic and decide how to handle in-flight work before stopping coordination components.
Repeated start() or stop() calls continue to delegate to the components. ComponentSet does not maintain its own idempotency state. A custom lifecycle-capable registry shared by several component sets therefore needs idempotent startup and non-destructive shutdown, or it must be owned by only one lifecycle boundary.
Host lifecycle pattern
components = create_redis_components(
redis_client=redis_client,
node_id="app-1",
auth_provider=auth_provider,
deployment_id=deployment_id,
)
await components.start()
try:
await serve_application()
finally:
await components.stop()
In a real host, place network startup and readiness between component startup and traffic acceptance. On shutdown, stop or drain the network roles before component cleanup. After every dependent component set has stopped, the owner that created the Redis client, payload store, tracer provider, and application resources closes them.
ComponentSet.stop() deliberately does not perform final shutdown on a shared tracer. The general tracer interface does not require a shutdown() method, and one tracer can be shared by several component sets.
Readiness is role-specific
A successful ComponentSet.start() means the recognized hooks completed. It does not prove:
- that an HTTP or WebSocket listener is bound and externally reachable;
- that a reverse proxy forwards trusted scheme and identity information correctly;
- that all other processes in the deployment use the same namespace and compatible config;
- that any browser, console, web, or mobile client is connected;
- that optional parsers, workers, dashboards, diagnostics, or product services are running;
- that a background listener which fails later will restart itself;
- that retained command and history capacity are healthy for the intended load.
Define readiness for the role the process serves. A WebSocket process needs its public edge and live-delivery coordination. A REST process needs authenticated ingestion and writable evidence storage. An App process needs dispatch, correlation, history, and its product dependencies. A combined process needs all of them.
Liveness and readiness are also different. A process can be alive while a Redis listener has failed, a payload store is unavailable, or the externally advertised REST endpoint is wrong. Use the diagnostics and observability facilities appropriate to the deployment rather than treating object construction as a permanent health signal.
Distributed ownership checklist
For every cooperating process:
- use the same stable deployment ID and compatible shared services;
- use a unique node ID during overlapping process lifetimes;
- start the component set before accepting dependent traffic;
- wire REST and App to compatible response notifiers;
- configure role-specific network limits and trusted transport information;
- drain or stop role traffic before component shutdown;
- close caller-owned shared resources only after their last consumer stops.
The next layer is the product-facing Application API. For deployment-level controls around these roles, see Secure the complete boundary.