Skip to main content

orion_error/core/
universal.rs

1use thiserror::Error;
2
3use super::{DomainReason, ErrorCategory, ErrorCode, ErrorIdentityProvider};
4
5/// Configuration error sub-classification
6/// 配置错误子分类
7#[derive(Debug, Error, PartialEq, Clone)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize))]
9pub enum ConfErrReason {
10    #[error("core config")]
11    Core,
12    #[error("feature config error")]
13    Feature,
14    #[error("dynamic config error")]
15    Dynamic,
16}
17
18/// Universal error reason classification with clear hierarchical structure
19/// 统一错误原因分类 - 采用清晰的分层结构
20///
21/// # Error Code Ranges
22/// - 100-199: Business Layer Errors (业务层错误)
23/// - 200-299: Infrastructure Layer Errors (基础设施层错误)
24/// - 300-399: Configuration & External Layer Errors (配置和外部层错误)
25#[derive(Debug, Error, PartialEq, Clone)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize))]
27pub enum UvsReason {
28    // === Business Layer Errors (100-199) ===
29    /// Input validation errors (格式错误、参数校验失败等)
30    #[error("validation error")]
31    ValidationError,
32
33    /// Business logic rule violations (业务规则违反、状态冲突等)
34    #[error("business logic error")]
35    BusinessError,
36
37    /// Business logic rule violations (业务规则违反、状态冲突等)
38    #[error("run rule error")]
39    RunRuleError,
40
41    /// Resource not found (查询的资源不存在)
42    #[error("not found error")]
43    NotFoundError,
44
45    /// Permission and authorization errors (权限不足、认证失败)
46    #[error("permission error")]
47    PermissionError,
48
49    // === Infrastructure Layer Errors (200-299) ===
50    /// Database and data processing errors (数据库操作、数据格式错误)
51    #[error("data error")]
52    DataError,
53
54    /// File system and OS-level errors (文件系统、操作系统错误)
55    #[error("system error")]
56    SystemError,
57
58    /// Network connectivity and protocol errors (网络连接、HTTP请求错误)
59    #[error("network error")]
60    NetworkError,
61
62    /// Resource exhaustion (内存不足、磁盘空间不足等)
63    #[error("resource error")]
64    ResourceError,
65
66    /// Operation timeouts (操作超时)
67    #[error("timeout error")]
68    TimeoutError,
69
70    // === Configuration & External Layer Errors (300-399) ===
71    /// Configuration-related errors (配置相关错误)
72    #[error("configuration error << {0}")]
73    ConfigError(ConfErrReason),
74
75    /// Third-party service errors (第三方服务错误)
76    #[error("external service error")]
77    ExternalError,
78
79    /// Third-party service errors (第三方服务错误)
80    #[error("BUG :logic error")]
81    LogicError,
82}
83
84impl DomainReason for UvsReason {}
85
86impl UvsReason {
87    // === Configuration Error Constructors ===
88    pub fn core_conf() -> Self {
89        Self::ConfigError(ConfErrReason::Core)
90    }
91
92    pub fn feature_conf() -> Self {
93        Self::ConfigError(ConfErrReason::Feature)
94    }
95
96    pub fn dynamic_conf() -> Self {
97        Self::ConfigError(ConfErrReason::Dynamic)
98    }
99
100    // === Business Layer Constructors ===
101    pub fn validation_error() -> Self {
102        Self::ValidationError
103    }
104
105    pub fn business_error() -> Self {
106        Self::BusinessError
107    }
108
109    pub fn rule_error() -> Self {
110        Self::RunRuleError
111    }
112
113    pub fn not_found_error() -> Self {
114        Self::NotFoundError
115    }
116
117    pub fn permission_error() -> Self {
118        Self::PermissionError
119    }
120
121    // === Infrastructure Layer Constructors ===
122    pub fn data_error() -> Self {
123        Self::DataError
124    }
125
126    pub fn system_error() -> Self {
127        Self::SystemError
128    }
129
130    pub fn network_error() -> Self {
131        Self::NetworkError
132    }
133
134    pub fn resource_error() -> Self {
135        Self::ResourceError
136    }
137
138    pub fn timeout_error() -> Self {
139        Self::TimeoutError
140    }
141
142    // === External Layer Constructors ===
143    pub fn external_error() -> Self {
144        Self::ExternalError
145    }
146
147    pub fn logic_error() -> Self {
148        Self::LogicError
149    }
150}
151
152/// Unified constructor helpers for types that can be converted from `UvsReason`.
153pub trait UvsFrom: From<UvsReason> + Sized {
154    fn from_conf() -> Self {
155        Self::from(UvsReason::core_conf())
156    }
157
158    fn from_conf_reason(reason: ConfErrReason) -> Self {
159        Self::from(UvsReason::ConfigError(reason))
160    }
161
162    fn from_data() -> Self {
163        Self::from(UvsReason::data_error())
164    }
165
166    fn from_sys() -> Self {
167        Self::from(UvsReason::system_error())
168    }
169
170    fn from_biz() -> Self {
171        Self::from(UvsReason::business_error())
172    }
173
174    fn from_logic() -> Self {
175        Self::from(UvsReason::logic_error())
176    }
177
178    fn from_rule() -> Self {
179        Self::from(UvsReason::rule_error())
180    }
181
182    fn from_res() -> Self {
183        Self::from(UvsReason::resource_error())
184    }
185
186    fn from_net() -> Self {
187        Self::from(UvsReason::network_error())
188    }
189
190    fn from_timeout() -> Self {
191        Self::from(UvsReason::timeout_error())
192    }
193
194    fn from_validation() -> Self {
195        Self::from(UvsReason::validation_error())
196    }
197
198    fn from_not_found() -> Self {
199        Self::from(UvsReason::not_found_error())
200    }
201
202    fn from_permission() -> Self {
203        Self::from(UvsReason::permission_error())
204    }
205
206    fn from_external() -> Self {
207        Self::from(UvsReason::external_error())
208    }
209}
210
211impl<T> UvsFrom for T where T: From<UvsReason> {}
212
213impl ErrorCode for UvsReason {
214    fn error_code(&self) -> i32 {
215        match self {
216            // === Business Layer Errors (100-199) ===
217            UvsReason::ValidationError => 100,
218            UvsReason::BusinessError => 101,
219            UvsReason::NotFoundError => 102,
220            UvsReason::PermissionError => 103,
221            UvsReason::LogicError => 104,
222            UvsReason::RunRuleError => 105,
223
224            // === Infrastructure Layer Errors (200-299) ===
225            UvsReason::DataError => 200,
226            UvsReason::SystemError => 201,
227            UvsReason::NetworkError => 202,
228            UvsReason::ResourceError => 203,
229            UvsReason::TimeoutError => 204,
230
231            // === Configuration & External Layer Errors (300-399) ===
232            UvsReason::ConfigError(_) => 300,
233            UvsReason::ExternalError => 301,
234        }
235    }
236}
237
238impl ErrorIdentityProvider for UvsReason {
239    fn stable_code(&self) -> &'static str {
240        match self {
241            UvsReason::ValidationError => "biz.validation_error",
242            UvsReason::BusinessError => "biz.business_error",
243            UvsReason::RunRuleError => "biz.run_rule_error",
244            UvsReason::NotFoundError => "biz.not_found",
245            UvsReason::PermissionError => "biz.permission_denied",
246            UvsReason::DataError => "sys.data_error",
247            UvsReason::SystemError => "sys.io_error",
248            UvsReason::NetworkError => "sys.network_error",
249            UvsReason::ResourceError => "sys.resource_exhausted",
250            UvsReason::TimeoutError => "sys.timeout",
251            UvsReason::ConfigError(ConfErrReason::Core) => "conf.core_invalid",
252            UvsReason::ConfigError(ConfErrReason::Feature) => "conf.feature_invalid",
253            UvsReason::ConfigError(ConfErrReason::Dynamic) => "conf.dynamic_invalid",
254            UvsReason::ExternalError => "sys.external_service_error",
255            UvsReason::LogicError => "logic.internal_invariant_broken",
256        }
257    }
258
259    fn error_category(&self) -> ErrorCategory {
260        match self {
261            UvsReason::ConfigError(_) => ErrorCategory::Conf,
262            UvsReason::LogicError => ErrorCategory::Logic,
263            UvsReason::ValidationError
264            | UvsReason::BusinessError
265            | UvsReason::RunRuleError
266            | UvsReason::NotFoundError
267            | UvsReason::PermissionError => ErrorCategory::Biz,
268            UvsReason::DataError
269            | UvsReason::SystemError
270            | UvsReason::NetworkError
271            | UvsReason::ResourceError
272            | UvsReason::TimeoutError
273            | UvsReason::ExternalError => ErrorCategory::Sys,
274        }
275    }
276}
277
278impl UvsReason {
279    /// Check if this error is retryable
280    /// 检查错误是否可重试
281    pub fn is_retryable(&self) -> bool {
282        match self {
283            // Infrastructure errors are often retryable
284            UvsReason::NetworkError => true,
285            UvsReason::TimeoutError => true,
286            UvsReason::ResourceError => true,
287            UvsReason::SystemError => true,
288            UvsReason::ExternalError => true,
289
290            // Business logic errors are generally not retryable
291            UvsReason::ValidationError => false,
292            UvsReason::BusinessError => false,
293            UvsReason::RunRuleError => false,
294            UvsReason::NotFoundError => false,
295            UvsReason::PermissionError => false,
296
297            // Configuration errors require manual intervention
298            UvsReason::ConfigError(_) => false,
299            UvsReason::DataError => false,
300            UvsReason::LogicError => false,
301        }
302    }
303
304    /// Check if this error should be logged with high severity
305    /// 检查错误是否需要高优先级记录
306    pub fn is_high_severity(&self) -> bool {
307        match self {
308            // System and infrastructure issues are high severity
309            UvsReason::SystemError => true,
310            UvsReason::ResourceError => true,
311            UvsReason::ConfigError(_) => true,
312
313            // Others are normal business operations
314            _ => false,
315        }
316    }
317
318    /// Get error category name for monitoring and metrics
319    /// 获取错误类别名称用于监控和指标
320    pub fn category_name(&self) -> &'static str {
321        match self {
322            UvsReason::ValidationError => "validation",
323            UvsReason::BusinessError => "business",
324            UvsReason::RunRuleError => "runrule",
325            UvsReason::NotFoundError => "not_found",
326            UvsReason::PermissionError => "permission",
327            UvsReason::DataError => "data",
328            UvsReason::SystemError => "system",
329            UvsReason::NetworkError => "network",
330            UvsReason::ResourceError => "resource",
331            UvsReason::TimeoutError => "timeout",
332            UvsReason::ConfigError(_) => "config",
333            UvsReason::ExternalError => "external",
334            UvsReason::LogicError => "logic",
335        }
336    }
337}
338
339#[cfg(test)]
340mod tests {
341    use super::*;
342
343    #[test]
344    fn test_error_code_ranges() {
345        // Business layer (100-199)
346        assert_eq!(UvsReason::validation_error().error_code(), 100);
347        assert_eq!(UvsReason::business_error().error_code(), 101);
348        assert_eq!(UvsReason::not_found_error().error_code(), 102);
349        assert_eq!(UvsReason::permission_error().error_code(), 103);
350
351        // Infrastructure layer (200-299)
352        assert_eq!(UvsReason::data_error().error_code(), 200);
353        assert_eq!(UvsReason::system_error().error_code(), 201);
354        assert_eq!(UvsReason::network_error().error_code(), 202);
355        assert_eq!(UvsReason::resource_error().error_code(), 203);
356        assert_eq!(UvsReason::timeout_error().error_code(), 204);
357
358        // Configuration & external layer (300-399)
359        assert_eq!(UvsReason::core_conf().error_code(), 300);
360        assert_eq!(UvsReason::external_error().error_code(), 301);
361    }
362
363    #[test]
364    fn test_retryable_errors() {
365        assert!(UvsReason::network_error().is_retryable());
366        assert!(UvsReason::timeout_error().is_retryable());
367        assert!(!UvsReason::validation_error().is_retryable());
368        assert!(!UvsReason::business_error().is_retryable());
369    }
370
371    #[test]
372    fn test_high_severity_errors() {
373        assert!(UvsReason::system_error().is_high_severity());
374        assert!(UvsReason::resource_error().is_high_severity());
375        assert!(!UvsReason::validation_error().is_high_severity());
376        assert!(!UvsReason::NotFoundError.is_high_severity());
377    }
378
379    #[test]
380    fn test_category_names() {
381        assert_eq!(UvsReason::network_error().category_name(), "network");
382        assert_eq!(UvsReason::business_error().category_name(), "business");
383        assert_eq!(UvsReason::core_conf().category_name(), "config");
384    }
385
386    #[test]
387    fn test_stable_code_values() {
388        assert_eq!(
389            UvsReason::validation_error().stable_code(),
390            "biz.validation_error"
391        );
392        assert_eq!(UvsReason::system_error().stable_code(), "sys.io_error");
393        assert_eq!(UvsReason::core_conf().stable_code(), "conf.core_invalid");
394        assert_eq!(
395            UvsReason::logic_error().stable_code(),
396            "logic.internal_invariant_broken"
397        );
398    }
399
400    #[test]
401    fn test_error_categories() {
402        assert_eq!(
403            UvsReason::validation_error().error_category(),
404            ErrorCategory::Biz
405        );
406        assert_eq!(
407            UvsReason::system_error().error_category(),
408            ErrorCategory::Sys
409        );
410        assert_eq!(UvsReason::core_conf().error_category(), ErrorCategory::Conf);
411        assert_eq!(
412            UvsReason::logic_error().error_category(),
413            ErrorCategory::Logic
414        );
415        assert_eq!(ErrorCategory::Biz.as_str(), "biz");
416    }
417
418    #[test]
419    fn test_trait_implementations() {
420        let reason: UvsReason = <UvsReason as UvsFrom>::from_net();
421        assert_eq!(reason.error_code(), 202);
422
423        let reason: UvsReason = <UvsReason as UvsFrom>::from_validation();
424        assert_eq!(reason.error_code(), 100);
425
426        let reason: UvsReason = <UvsReason as UvsFrom>::from_external();
427        assert_eq!(reason.error_code(), 301);
428        assert_eq!(reason.error_category(), ErrorCategory::Sys);
429    }
430}