lightshuttle_runtime/lifecycle/status.rs
1//! Per-node status and lifecycle event types.
2//!
3//! [`NodeStatus`] is the fine-grained internal status carried by each
4//! `tokio::sync::watch` channel inside the manager. [`LifecycleEvent`] is the
5//! externally broadcast event emitted on the `tokio::sync::broadcast` channel
6//! returned by [`crate::LifecycleManager::subscribe_events`].
7//!
8//! The two types serve different consumers: `NodeStatus` is used internally by
9//! `start_one` to gate dependency ordering; `LifecycleEvent` is consumed by
10//! CLI progress bars, dashboard WebSocket connections, and test assertions.
11
12use serde::Serialize;
13
14/// Lifecycle status of a single managed resource.
15///
16/// Broadcast through a `tokio::sync::watch` channel so dependents can
17/// wait for their dependencies to become ready without polling.
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub enum NodeStatus {
20 /// The resource has not been started yet.
21 Pending,
22 /// The runtime accepted the start request; the container is booting.
23 Starting,
24 /// The container is up but does not declare a healthcheck or has
25 /// not produced a healthcheck result yet.
26 Running,
27 /// The container is up and reports a successful healthcheck.
28 Healthy,
29 /// The resource entered a terminal failure state with the recorded
30 /// reason.
31 Failed {
32 /// Free-form failure reason for diagnostics.
33 reason: String,
34 },
35 /// The resource has been stopped on request.
36 Stopped,
37}
38
39impl NodeStatus {
40 /// Whether the resource is considered ready for dependents to
41 /// start on top of it.
42 #[must_use]
43 pub fn is_ready(&self) -> bool {
44 matches!(self, Self::Healthy | Self::Running)
45 }
46
47 /// Whether the resource is in a terminal state (failed or stopped).
48 #[must_use]
49 pub fn is_terminal(&self) -> bool {
50 matches!(self, Self::Failed { .. } | Self::Stopped)
51 }
52}
53
54/// Event emitted by [`crate::LifecycleManager`] for consumption by a
55/// CLI, dashboard or test harness.
56#[derive(Debug, Clone, Serialize)]
57#[serde(tag = "type", rename_all = "snake_case")]
58pub enum LifecycleEvent {
59 /// A resource has been created and started by the runtime.
60 ResourceStarted {
61 /// Resource name as declared in the manifest.
62 name: String,
63 /// Container identifier returned by the runtime.
64 container_id: String,
65 },
66 /// A resource passed its healthcheck.
67 ResourceHealthy {
68 /// Resource name.
69 name: String,
70 },
71 /// A resource failed and will not run.
72 ResourceFailed {
73 /// Resource name.
74 name: String,
75 /// Human-readable failure description.
76 error: String,
77 },
78 /// A resource has been stopped cleanly.
79 ResourceStopped {
80 /// Resource name.
81 name: String,
82 },
83 /// Every resource has reached a ready state.
84 StackStarted,
85 /// The manager has started rolling the stack down.
86 StackStopping,
87 /// Every resource has been stopped.
88 StackStopped,
89}