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 UnifiedReason {
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 UnifiedReason {}
85
86impl UnifiedReason {
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
152impl ErrorCode for UnifiedReason {
153    fn error_code(&self) -> i32 {
154        match self {
155            // === Business Layer Errors (100-199) ===
156            UnifiedReason::ValidationError => 100,
157            UnifiedReason::BusinessError => 101,
158            UnifiedReason::NotFoundError => 102,
159            UnifiedReason::PermissionError => 103,
160            UnifiedReason::LogicError => 104,
161            UnifiedReason::RunRuleError => 105,
162
163            // === Infrastructure Layer Errors (200-299) ===
164            UnifiedReason::DataError => 200,
165            UnifiedReason::SystemError => 201,
166            UnifiedReason::NetworkError => 202,
167            UnifiedReason::ResourceError => 203,
168            UnifiedReason::TimeoutError => 204,
169
170            // === Configuration & External Layer Errors (300-399) ===
171            UnifiedReason::ConfigError(_) => 300,
172            UnifiedReason::ExternalError => 301,
173        }
174    }
175}
176
177impl ErrorIdentityProvider for UnifiedReason {
178    fn stable_code(&self) -> &'static str {
179        match self {
180            UnifiedReason::ValidationError => "biz.validation_error",
181            UnifiedReason::BusinessError => "biz.business_error",
182            UnifiedReason::RunRuleError => "biz.run_rule_error",
183            UnifiedReason::NotFoundError => "biz.not_found",
184            UnifiedReason::PermissionError => "biz.permission_denied",
185            UnifiedReason::DataError => "sys.data_error",
186            UnifiedReason::SystemError => "sys.io_error",
187            UnifiedReason::NetworkError => "sys.network_error",
188            UnifiedReason::ResourceError => "sys.resource_exhausted",
189            UnifiedReason::TimeoutError => "sys.timeout",
190            UnifiedReason::ConfigError(ConfErrReason::Core) => "conf.core_invalid",
191            UnifiedReason::ConfigError(ConfErrReason::Feature) => "conf.feature_invalid",
192            UnifiedReason::ConfigError(ConfErrReason::Dynamic) => "conf.dynamic_invalid",
193            UnifiedReason::ExternalError => "sys.external_service_error",
194            UnifiedReason::LogicError => "logic.internal_invariant_broken",
195        }
196    }
197
198    fn error_category(&self) -> ErrorCategory {
199        match self {
200            UnifiedReason::ConfigError(_) => ErrorCategory::Conf,
201            UnifiedReason::LogicError => ErrorCategory::Logic,
202            UnifiedReason::ValidationError
203            | UnifiedReason::BusinessError
204            | UnifiedReason::RunRuleError
205            | UnifiedReason::NotFoundError
206            | UnifiedReason::PermissionError => ErrorCategory::Biz,
207            UnifiedReason::DataError
208            | UnifiedReason::SystemError
209            | UnifiedReason::NetworkError
210            | UnifiedReason::ResourceError
211            | UnifiedReason::TimeoutError
212            | UnifiedReason::ExternalError => ErrorCategory::Sys,
213        }
214    }
215}
216
217impl UnifiedReason {
218    /// Check if this error is retryable
219    /// 检查错误是否可重试
220    pub fn is_retryable(&self) -> bool {
221        match self {
222            // Infrastructure errors are often retryable
223            UnifiedReason::NetworkError => true,
224            UnifiedReason::TimeoutError => true,
225            UnifiedReason::ResourceError => true,
226            UnifiedReason::SystemError => true,
227            UnifiedReason::ExternalError => true,
228
229            // Business logic errors are generally not retryable
230            UnifiedReason::ValidationError => false,
231            UnifiedReason::BusinessError => false,
232            UnifiedReason::RunRuleError => false,
233            UnifiedReason::NotFoundError => false,
234            UnifiedReason::PermissionError => false,
235
236            // Configuration errors require manual intervention
237            UnifiedReason::ConfigError(_) => false,
238            UnifiedReason::DataError => false,
239            UnifiedReason::LogicError => false,
240        }
241    }
242
243    /// Check if this error should be logged with high severity
244    /// 检查错误是否需要高优先级记录
245    pub fn is_high_severity(&self) -> bool {
246        match self {
247            // System and infrastructure issues are high severity
248            UnifiedReason::SystemError => true,
249            UnifiedReason::ResourceError => true,
250            UnifiedReason::ConfigError(_) => true,
251
252            // Others are normal business operations
253            _ => false,
254        }
255    }
256
257    /// Get error category name for monitoring and metrics
258    /// 获取错误类别名称用于监控和指标
259    pub fn category_name(&self) -> &'static str {
260        match self {
261            UnifiedReason::ValidationError => "validation",
262            UnifiedReason::BusinessError => "business",
263            UnifiedReason::RunRuleError => "runrule",
264            UnifiedReason::NotFoundError => "not_found",
265            UnifiedReason::PermissionError => "permission",
266            UnifiedReason::DataError => "data",
267            UnifiedReason::SystemError => "system",
268            UnifiedReason::NetworkError => "network",
269            UnifiedReason::ResourceError => "resource",
270            UnifiedReason::TimeoutError => "timeout",
271            UnifiedReason::ConfigError(_) => "config",
272            UnifiedReason::ExternalError => "external",
273            UnifiedReason::LogicError => "logic",
274        }
275    }
276}
277
278/// Deprecated: use [`UnifiedReason`] instead.
279#[deprecated(since = "0.9.0", note = "renamed to UnifiedReason")]
280#[allow(dead_code)]
281pub type UvsReason = UnifiedReason;
282
283#[cfg(test)]
284mod tests {
285    use super::*;
286
287    #[test]
288    fn test_error_code_ranges() {
289        // Business layer (100-199)
290        assert_eq!(UnifiedReason::validation_error().error_code(), 100);
291        assert_eq!(UnifiedReason::business_error().error_code(), 101);
292        assert_eq!(UnifiedReason::not_found_error().error_code(), 102);
293        assert_eq!(UnifiedReason::permission_error().error_code(), 103);
294
295        // Infrastructure layer (200-299)
296        assert_eq!(UnifiedReason::data_error().error_code(), 200);
297        assert_eq!(UnifiedReason::system_error().error_code(), 201);
298        assert_eq!(UnifiedReason::network_error().error_code(), 202);
299        assert_eq!(UnifiedReason::resource_error().error_code(), 203);
300        assert_eq!(UnifiedReason::timeout_error().error_code(), 204);
301
302        // Configuration & external layer (300-399)
303        assert_eq!(UnifiedReason::core_conf().error_code(), 300);
304        assert_eq!(UnifiedReason::external_error().error_code(), 301);
305    }
306
307    #[test]
308    fn test_retryable_errors() {
309        assert!(UnifiedReason::network_error().is_retryable());
310        assert!(UnifiedReason::timeout_error().is_retryable());
311        assert!(!UnifiedReason::validation_error().is_retryable());
312        assert!(!UnifiedReason::business_error().is_retryable());
313    }
314
315    #[test]
316    fn test_high_severity_errors() {
317        assert!(UnifiedReason::system_error().is_high_severity());
318        assert!(UnifiedReason::resource_error().is_high_severity());
319        assert!(!UnifiedReason::validation_error().is_high_severity());
320        assert!(!UnifiedReason::NotFoundError.is_high_severity());
321    }
322
323    #[test]
324    fn test_category_names() {
325        assert_eq!(UnifiedReason::network_error().category_name(), "network");
326        assert_eq!(UnifiedReason::business_error().category_name(), "business");
327        assert_eq!(UnifiedReason::core_conf().category_name(), "config");
328    }
329
330    #[test]
331    fn test_stable_code_values() {
332        assert_eq!(
333            UnifiedReason::validation_error().stable_code(),
334            "biz.validation_error"
335        );
336        assert_eq!(UnifiedReason::system_error().stable_code(), "sys.io_error");
337        assert_eq!(
338            UnifiedReason::core_conf().stable_code(),
339            "conf.core_invalid"
340        );
341        assert_eq!(
342            UnifiedReason::logic_error().stable_code(),
343            "logic.internal_invariant_broken"
344        );
345    }
346
347    #[test]
348    fn test_error_categories() {
349        assert_eq!(
350            UnifiedReason::validation_error().error_category(),
351            ErrorCategory::Biz
352        );
353        assert_eq!(
354            UnifiedReason::system_error().error_category(),
355            ErrorCategory::Sys
356        );
357        assert_eq!(
358            UnifiedReason::core_conf().error_category(),
359            ErrorCategory::Conf
360        );
361        assert_eq!(
362            UnifiedReason::logic_error().error_category(),
363            ErrorCategory::Logic
364        );
365        assert_eq!(ErrorCategory::Biz.as_str(), "biz");
366    }
367
368    #[test]
369    fn test_trait_implementations() {
370        let reason = UnifiedReason::network_error();
371        assert_eq!(reason.error_code(), 202);
372
373        let reason = UnifiedReason::validation_error();
374        assert_eq!(reason.error_code(), 100);
375
376        let reason = UnifiedReason::external_error();
377        assert_eq!(reason.error_code(), 301);
378        assert_eq!(reason.error_category(), ErrorCategory::Sys);
379    }
380}