Skip to main content

Mountain/Error/
ServiceError.rs

1//! # Service Error Types
2//!
3//! Service-related error types for Mountain.
4//! Covers service discovery, lifecycle transitions (start, stop,
5//! already-running, not-running), operation timeout, and dependency
6//! resolution failures.
7
8use std::{error::Error as StdError, fmt};
9
10use serde::{Deserialize, Serialize};
11
12use super::CoreError::{ErrorContext, ErrorKind, ErrorSeverity, MountainError};
13
14/// Service operation error types.
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub enum ServiceError {
17	/// Service not found.
18	ServiceNotFound { context:ErrorContext, service_name:String },
19
20	/// Service initialization failed.
21	InitializationFailed { context:ErrorContext, service_name:String, source:Option<String> },
22
23	/// Service already running.
24	AlreadyRunning { context:ErrorContext, service_name:String },
25
26	/// Service not running.
27	NotRunning { context:ErrorContext, service_name:String },
28
29	/// Service start failed.
30	StartFailed { context:ErrorContext, service_name:String, source:Option<String> },
31
32	/// Service stop failed.
33	StopFailed { context:ErrorContext, service_name:String, source:Option<String> },
34
35	/// Service timeout.
36	Timeout { context:ErrorContext, service_name:String, operation:String, timeout_ms:u64 },
37
38	/// Service dependency error.
39	DependencyError { context:ErrorContext, service_name:String, dependency:String },
40}
41
42impl ServiceError {
43	/// Get the error context.
44	pub fn context(&self) -> &ErrorContext {
45		match self {
46			ServiceError::ServiceNotFound { context, .. } => context,
47
48			ServiceError::InitializationFailed { context, .. } => context,
49
50			ServiceError::AlreadyRunning { context, .. } => context,
51
52			ServiceError::NotRunning { context, .. } => context,
53
54			ServiceError::StartFailed { context, .. } => context,
55
56			ServiceError::StopFailed { context, .. } => context,
57
58			ServiceError::Timeout { context, .. } => context,
59
60			ServiceError::DependencyError { context, .. } => context,
61		}
62	}
63
64	/// Create a service not found error.
65	pub fn service_not_found(service_name:impl Into<String>) -> Self {
66		let service_name_str = service_name.into();
67
68		Self::ServiceNotFound {
69			context:ErrorContext::new(format!("Service not found: {}", service_name_str))
70				.with_kind(ErrorKind::Service)
71				.with_severity(ErrorSeverity::Error),
72
73			service_name:service_name_str,
74		}
75	}
76
77	/// Create an initialization failed error.
78	pub fn initialization_failed(service_name:impl Into<String>, source:Option<String>) -> Self {
79		let service_name_str = service_name.into();
80
81		Self::InitializationFailed {
82			context:ErrorContext::new(format!("Service initialization failed: {}", service_name_str))
83				.with_kind(ErrorKind::Service)
84				.with_severity(ErrorSeverity::Critical),
85
86			service_name:service_name_str,
87
88			source,
89		}
90	}
91
92	/// Create an already running error.
93	pub fn already_running(service_name:impl Into<String>) -> Self {
94		let service_name_str = service_name.into();
95
96		Self::AlreadyRunning {
97			context:ErrorContext::new(format!("Service already running: {}", service_name_str))
98				.with_kind(ErrorKind::Service)
99				.with_severity(ErrorSeverity::Warning),
100
101			service_name:service_name_str,
102		}
103	}
104
105	/// Create a not running error.
106	pub fn not_running(service_name:impl Into<String>) -> Self {
107		let service_name_str = service_name.into();
108
109		Self::NotRunning {
110			context:ErrorContext::new(format!("Service not running: {}", service_name_str))
111				.with_kind(ErrorKind::Service)
112				.with_severity(ErrorSeverity::Error),
113
114			service_name:service_name_str,
115		}
116	}
117
118	/// Create a start failed error.
119	pub fn start_failed(service_name:impl Into<String>, source:Option<String>) -> Self {
120		let service_name_str = service_name.into();
121
122		Self::StartFailed {
123			context:ErrorContext::new(format!("Service start failed: {}", service_name_str))
124				.with_kind(ErrorKind::Service)
125				.with_severity(ErrorSeverity::Error),
126
127			service_name:service_name_str,
128
129			source,
130		}
131	}
132
133	/// Create a timeout error.
134	pub fn timeout(service_name:impl Into<String>, operation:impl Into<String>, timeout_ms:u64) -> Self {
135		let service_name_str = service_name.into();
136
137		let operation_str = operation.into();
138
139		Self::Timeout {
140			context:ErrorContext::new(format!(
141				"Service timeout: {} operation timed out after {}ms",
142				service_name_str, timeout_ms
143			))
144			.with_kind(ErrorKind::Service)
145			.with_severity(ErrorSeverity::Error)
146			.with_operation(operation_str.clone()),
147
148			service_name:service_name_str,
149
150			operation:operation_str,
151
152			timeout_ms,
153		}
154	}
155
156	/// Create a dependency error.
157	pub fn dependency_error(service_name:impl Into<String>, dependency:impl Into<String>) -> Self {
158		let service_name_str = service_name.into();
159
160		let dependency_str = dependency.into();
161
162		Self::DependencyError {
163			context:ErrorContext::new(format!(
164				"Service dependency error: {} depends on {}",
165				service_name_str, dependency_str
166			))
167			.with_kind(ErrorKind::Service)
168			.with_severity(ErrorSeverity::Critical),
169
170			service_name:service_name_str,
171
172			dependency:dependency_str,
173		}
174	}
175}
176
177impl fmt::Display for ServiceError {
178	fn fmt(&self, f:&mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.context()) }
179}
180
181impl StdError for ServiceError {}
182
183impl From<ServiceError> for MountainError {
184	fn from(err:ServiceError) -> Self { MountainError::new(err.context().clone()).with_source(err.to_string()) }
185}