rskit_process/persistent/
error.rs1use crate::{AppError, ErrorCode};
2
3const PERSISTENT_START_ERROR_KIND_DETAIL: &str = "rskit_process.persistent_start_error_kind";
4
5#[derive(Debug, Clone, Copy, Eq, PartialEq)]
7#[non_exhaustive]
8pub enum PersistentStartErrorKind {
9 SpawnFailed,
11 ReadinessCommandTimedOut,
13 ReadinessCommandFailed,
15 ReadinessTimedOut,
17 OutputEndedBeforeReadiness,
19 ExitedBeforeReadiness,
21}
22
23impl PersistentStartErrorKind {
24 const fn as_str(self) -> &'static str {
25 match self {
26 Self::SpawnFailed => "spawn_failed",
27 Self::ReadinessCommandTimedOut => "readiness_command_timed_out",
28 Self::ReadinessCommandFailed => "readiness_command_failed",
29 Self::ReadinessTimedOut => "readiness_timed_out",
30 Self::OutputEndedBeforeReadiness => "output_ended_before_readiness",
31 Self::ExitedBeforeReadiness => "exited_before_readiness",
32 }
33 }
34
35 fn from_str(value: &str) -> Option<Self> {
36 match value {
37 "spawn_failed" => Some(Self::SpawnFailed),
38 "readiness_command_timed_out" => Some(Self::ReadinessCommandTimedOut),
39 "readiness_command_failed" => Some(Self::ReadinessCommandFailed),
40 "readiness_timed_out" => Some(Self::ReadinessTimedOut),
41 "output_ended_before_readiness" => Some(Self::OutputEndedBeforeReadiness),
42 "exited_before_readiness" => Some(Self::ExitedBeforeReadiness),
43 _ => None,
44 }
45 }
46}
47
48pub fn persistent_start_error_kind(error: &AppError) -> Option<PersistentStartErrorKind> {
50 error
51 .details()
52 .get(PERSISTENT_START_ERROR_KIND_DETAIL)
53 .and_then(|value| value.as_str())
54 .and_then(PersistentStartErrorKind::from_str)
55}
56
57pub(in crate::persistent) fn persistent_start_error(
58 kind: PersistentStartErrorKind,
59 code: ErrorCode,
60 message: impl Into<String>,
61) -> AppError {
62 AppError::new(code, message).with_detail(PERSISTENT_START_ERROR_KIND_DETAIL, kind.as_str())
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn persistent_start_error_round_trips_all_structured_kinds() {
71 for kind in [
72 PersistentStartErrorKind::SpawnFailed,
73 PersistentStartErrorKind::ReadinessCommandTimedOut,
74 PersistentStartErrorKind::ReadinessCommandFailed,
75 PersistentStartErrorKind::ReadinessTimedOut,
76 PersistentStartErrorKind::OutputEndedBeforeReadiness,
77 PersistentStartErrorKind::ExitedBeforeReadiness,
78 ] {
79 let error = persistent_start_error(kind, ErrorCode::Internal, "failed");
80 assert_eq!(persistent_start_error_kind(&error), Some(kind));
81 }
82 }
83
84 #[test]
85 fn missing_or_unknown_persistent_error_kind_returns_none() {
86 assert_eq!(
87 persistent_start_error_kind(&AppError::new(ErrorCode::Internal, "plain")),
88 None
89 );
90 let error = AppError::new(ErrorCode::Internal, "bad")
91 .with_detail(PERSISTENT_START_ERROR_KIND_DETAIL, "unknown");
92 assert_eq!(persistent_start_error_kind(&error), None);
93 }
94}