feat(supervisor): restart-policy decision logic

This commit is contained in:
2026-05-25 11:34:50 +02:00
parent 1d2848f03a
commit 4837a73167
2 changed files with 108 additions and 0 deletions
+6
View File
@@ -1,5 +1,11 @@
//! Process-supervision primitives for the xy daemon.
pub mod backoff;
pub mod child;
pub mod policy;
pub mod retry_window;
pub use backoff::Backoff;
pub use child::{ChildHandle, MockChild, MockChildController};
pub use policy::{RestartDecision, decide};
pub use retry_window::RetryWindow;
+102
View File
@@ -0,0 +1,102 @@
use xy_protocol::RestartPolicy;
#[derive(Debug, PartialEq, Eq)]
pub enum RestartDecision {
Restart,
StayStopped,
MarkFailed,
}
pub fn decide(
policy: RestartPolicy,
exit_code: Option<i32>,
retry_cap_reached: bool,
) -> RestartDecision {
let clean = matches!(exit_code, Some(0));
let want = match policy {
RestartPolicy::Never => false,
RestartPolicy::OnFailure => !clean,
RestartPolicy::Always => true,
};
if !want {
return RestartDecision::StayStopped;
}
if retry_cap_reached {
RestartDecision::MarkFailed
} else {
RestartDecision::Restart
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn never_never_restarts() {
assert_eq!(
decide(RestartPolicy::Never, Some(0), false),
RestartDecision::StayStopped
);
assert_eq!(
decide(RestartPolicy::Never, Some(1), false),
RestartDecision::StayStopped
);
assert_eq!(
decide(RestartPolicy::Never, None, false),
RestartDecision::StayStopped
);
}
#[test]
fn on_failure_skips_clean() {
assert_eq!(
decide(RestartPolicy::OnFailure, Some(0), false),
RestartDecision::StayStopped
);
}
#[test]
fn on_failure_restarts_nonzero() {
assert_eq!(
decide(RestartPolicy::OnFailure, Some(1), false),
RestartDecision::Restart
);
}
#[test]
fn on_failure_restarts_signal() {
assert_eq!(
decide(RestartPolicy::OnFailure, None, false),
RestartDecision::Restart
);
}
#[test]
fn always_restarts_on_clean() {
assert_eq!(
decide(RestartPolicy::Always, Some(0), false),
RestartDecision::Restart
);
}
#[test]
fn cap_reached_marks_failed() {
assert_eq!(
decide(RestartPolicy::Always, Some(0), true),
RestartDecision::MarkFailed
);
assert_eq!(
decide(RestartPolicy::OnFailure, Some(1), true),
RestartDecision::MarkFailed
);
}
#[test]
fn cap_reached_never_still_stopped() {
assert_eq!(
decide(RestartPolicy::Never, Some(1), true),
RestartDecision::StayStopped
);
}
}