shep_core/status.rs
1//! Process lifecycle status
2
3use core::fmt;
4
5use serde::{Deserialize, Serialize};
6
7/// Lifecycle state of a sheep (one managed process)
8///
9/// The serialized strings are the wire contract; `waiting-restart` means a
10/// backoff or restart delay is pending.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12#[serde(rename_all = "kebab-case")]
13pub enum ProcStatus {
14 /// Spawned, not yet ready
15 Starting,
16 /// Running and (if configured) ready
17 Online,
18 /// This instance is going away and is not a restart target
19 ///
20 /// Set by whichever step marks the drainee before its replacement takes
21 /// the slot: `SpawnNew` for an overlap reload, `DrainOld` for a serial
22 /// one. Either way, the old and new instance never both count as
23 /// running. An operator's `stop` leaves a sheep `Online` through its
24 /// whole kill ladder instead; a scheduled or out-of-band restart must
25 /// reject a sheep in this status rather than race the replacement
26 /// taking over its slot.
27 Stopping,
28 /// Cleanly stopped; not scheduled to run
29 Stopped,
30 /// Restart budget exhausted or spawn failed
31 Errored,
32 /// Restart pending after a backoff or configured delay
33 WaitingRestart,
34}
35
36impl fmt::Display for ProcStatus {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 f.write_str(match self {
39 Self::Starting => "starting",
40 Self::Online => "online",
41 Self::Stopping => "stopping",
42 Self::Stopped => "stopped",
43 Self::Errored => "errored",
44 Self::WaitingRestart => "waiting-restart",
45 })
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn wire_strings_are_stable() {
55 let cases = [
56 (ProcStatus::Starting, "\"starting\""),
57 (ProcStatus::Online, "\"online\""),
58 (ProcStatus::Stopping, "\"stopping\""),
59 (ProcStatus::Stopped, "\"stopped\""),
60 (ProcStatus::Errored, "\"errored\""),
61 (ProcStatus::WaitingRestart, "\"waiting-restart\""),
62 ];
63 for (status, json) in cases {
64 assert_eq!(serde_json::to_string(&status).unwrap(), json);
65 assert_eq!(serde_json::from_str::<ProcStatus>(json).unwrap(), status);
66 assert_eq!(format!("\"{status}\""), json);
67 }
68 }
69}