Readiness, shutdown, and upgrades
Lifecycle is part of correctness. A process can be alive while its role cannot accept a connection, deliver a command, settle a result, or notify a waiter.
Define readiness by role
A WebSocket host is ready when its required component subscriptions are active, it can authenticate new clients, register routes, and own sockets at the advertised endpoint.
A REST host is ready when authentication, deduplication, history, correlation, and required payload storage are usable. Accepting a body while history is unavailable only moves the failure deeper into the request.
An application host is ready when it can read current routing, apply policy, dispatch, and observe outcomes according to its advertised API. An observation host is ready when its inspectors can reach the shared state they claim to expose.
Make degraded behavior explicit. A no-op tracer may be acceptable; an unavailable required history is not equivalent.
Start in dependency order
Create configuration and dependencies, start backing components and subscriptions, construct the node roles, then expose listeners and readiness. For Redis compositions, ComponentSet.start() initializes capability-dependent registry behavior that should be ready before client traffic arrives.
Run one internal functional probe that crosses delivery and return. A shallow health endpoint cannot validate advertised URLs, identity mapping, dispatcher ownership, or correlation.
Shut down without inventing certainty
- mark the process unready and stop admitting new traffic;
- drain or redirect new WebSocket connections;
- allow bounded in-flight work to settle or fence it according to role policy;
- stop listeners and consumers;
- stop the component sets, then let the host that created a shared OpenTelemetry tracer call its final
shutdown()and close Redis, payload stores, and product resources.
A forced shutdown can leave an attempt uncertain. Preserve command and product-operation identities so the next process can reconcile rather than replay blindly.
Upgrade protocol participants compatibly
Server and TypeScript client models form a cross-language contract. Rollouts may temporarily contain old and new clients and several server versions. Before changing a required field, message kind, action descriptor, or negotiation rule:
- update the Python and TypeScript models and translators;
- add positive, negative, and mixed-version tests;
- preserve or explicitly negotiate compatible behavior;
- update built-in action descriptors and public reference material;
- test reconnect, runtime replacement, and in-flight return across the rollout;
- define rollback while both storage and messages may contain the new shape.
Capability advertisement is currently a startup snapshot. When client actions change, restart or reconnect with a runtime built from the complete new handler set rather than relying on late registration to update the server.
Protect shared storage during rollout
Redis key namespaces depend on the stable deployment ID and component contracts. Do not point incompatible implementations at one live namespace without a migration plan. Treat payload-store schema, reducer state, parser identities, and retained-message consumers as versioned data contracts too.
Canary the real command journey, watch error-code and ingestion-rejection changes, and stop the rollout when evidence no longer joins across application, client, and history views.