1use thiserror::Error;
2
3#[derive(Error, Debug)]
8pub enum ForgeError {
9 #[error("状态错误: {message}")]
11 State {
12 message: String,
13 #[source]
14 source: Option<Box<dyn std::error::Error + Send + Sync>>,
15 },
16
17 #[error("事件错误: {message}")]
19 Event {
20 message: String,
21 #[source]
22 source: Option<Box<dyn std::error::Error + Send + Sync>>,
23 },
24
25 #[error("中间件错误: {message}")]
27 Middleware {
28 message: String,
29 middleware_name: Option<String>,
30 #[source]
31 source: Option<Box<dyn std::error::Error + Send + Sync>>,
32 },
33
34 #[error("扩展错误: {message}")]
36 Extension {
37 message: String,
38 extension_name: Option<String>,
39 #[source]
40 source: Option<Box<dyn std::error::Error + Send + Sync>>,
41 },
42
43 #[error("事务错误: {message}")]
45 Transaction {
46 message: String,
47 transaction_id: Option<u64>,
48 #[source]
49 source: Option<Box<dyn std::error::Error + Send + Sync>>,
50 },
51
52 #[error("历史记录错误: {message}")]
54 History {
55 message: String,
56 #[source]
57 source: Option<Box<dyn std::error::Error + Send + Sync>>,
58 },
59
60 #[error("配置错误: {message}")]
62 Config {
63 message: String,
64 config_key: Option<String>,
65 #[source]
66 source: Option<Box<dyn std::error::Error + Send + Sync>>,
67 },
68
69 #[error("存储错误: {message}")]
71 Storage {
72 message: String,
73 #[source]
74 source: Option<Box<dyn std::error::Error + Send + Sync>>,
75 },
76
77 #[error("缓存错误: {message}")]
79 Cache {
80 message: String,
81 #[source]
82 source: Option<Box<dyn std::error::Error + Send + Sync>>,
83 },
84
85 #[error("引擎错误: {message}")]
87 Engine {
88 message: String,
89 #[source]
90 source: Option<Box<dyn std::error::Error + Send + Sync>>,
91 },
92
93 #[error("操作超时: {operation} (超时时间: {timeout_ms}ms)")]
95 Timeout {
96 operation: String,
97 timeout_ms: u64,
98 },
99
100 #[error("资源不足: {resource_type}")]
102 ResourceExhausted {
103 resource_type: String,
104 current_usage: Option<usize>,
105 limit: Option<usize>,
106 },
107
108 #[error("并发错误: {message}")]
110 Concurrency {
111 message: String,
112 #[source]
113 source: Option<Box<dyn std::error::Error + Send + Sync>>,
114 },
115
116 #[error("验证失败: {message}")]
118 Validation {
119 message: String,
120 field: Option<String>,
121 },
122
123 #[error("外部依赖错误: {dependency}")]
125 ExternalDependency {
126 dependency: String,
127 #[source]
128 source: Box<dyn std::error::Error + Send + Sync>,
129 },
130
131 #[error("内部错误: {message}")]
133 Internal {
134 message: String,
135 location: Option<String>,
136 },
137
138 #[error("其他错误: {0}")]
140 Other(#[from] anyhow::Error),
141}
142
143pub type ForgeResult<T> = Result<T, ForgeError>;
145
146impl ForgeError {
147 pub fn error_code(&self) -> &'static str {
149 match self {
150 ForgeError::State { .. } => "STATE_ERROR",
151 ForgeError::Event { .. } => "EVENT_ERROR",
152 ForgeError::Middleware { .. } => "MIDDLEWARE_ERROR",
153 ForgeError::Extension { .. } => "EXTENSION_ERROR",
154 ForgeError::Transaction { .. } => "TRANSACTION_ERROR",
155 ForgeError::History { .. } => "HISTORY_ERROR",
156 ForgeError::Config { .. } => "CONFIG_ERROR",
157 ForgeError::Storage { .. } => "STORAGE_ERROR",
158 ForgeError::Cache { .. } => "CACHE_ERROR",
159 ForgeError::Engine { .. } => "ENGINE_ERROR",
160 ForgeError::Timeout { .. } => "TIMEOUT_ERROR",
161 ForgeError::ResourceExhausted { .. } => "RESOURCE_EXHAUSTED",
162 ForgeError::Concurrency { .. } => "CONCURRENCY_ERROR",
163 ForgeError::Validation { .. } => "VALIDATION_ERROR",
164 ForgeError::ExternalDependency { .. } => "EXTERNAL_DEPENDENCY_ERROR",
165 ForgeError::Internal { .. } => "INTERNAL_ERROR",
166 ForgeError::Other(_) => "OTHER_ERROR",
167 }
168 }
169
170 pub fn is_retryable(&self) -> bool {
172 matches!(
173 self,
174 ForgeError::Timeout { .. }
175 | ForgeError::ResourceExhausted { .. }
176 | ForgeError::Concurrency { .. }
177 | ForgeError::ExternalDependency { .. }
178 )
179 }
180
181 pub fn is_temporary(&self) -> bool {
183 matches!(
184 self,
185 ForgeError::Timeout { .. }
186 | ForgeError::ResourceExhausted { .. }
187 | ForgeError::Concurrency { .. }
188 )
189 }
190}
191
192pub mod error_utils {
197 use super::*;
198
199 pub fn map_error<T, E: std::error::Error + Send + Sync + 'static>(
201 result: Result<T, E>,
202 context: &str,
203 ) -> ForgeResult<T> {
204 result.map_err(|e| ForgeError::Other(anyhow::anyhow!("{}: {}", context, e)))
205 }
206
207 pub fn state_error(msg: impl Into<String>) -> ForgeError {
209 ForgeError::State {
210 message: msg.into(),
211 source: None,
212 }
213 }
214
215 pub fn state_error_with_source(
217 msg: impl Into<String>,
218 source: impl std::error::Error + Send + Sync + 'static,
219 ) -> ForgeError {
220 ForgeError::State {
221 message: msg.into(),
222 source: Some(Box::new(source)),
223 }
224 }
225
226 pub fn event_error(msg: impl Into<String>) -> ForgeError {
228 ForgeError::Event {
229 message: msg.into(),
230 source: None,
231 }
232 }
233
234 pub fn event_error_with_source(
236 msg: impl Into<String>,
237 source: impl std::error::Error + Send + Sync + 'static,
238 ) -> ForgeError {
239 ForgeError::Event {
240 message: msg.into(),
241 source: Some(Box::new(source)),
242 }
243 }
244
245 pub fn middleware_error(msg: impl Into<String>) -> ForgeError {
247 ForgeError::Middleware {
248 message: msg.into(),
249 middleware_name: None,
250 source: None,
251 }
252 }
253
254 pub fn middleware_error_with_name(
256 msg: impl Into<String>,
257 middleware_name: impl Into<String>,
258 ) -> ForgeError {
259 ForgeError::Middleware {
260 message: msg.into(),
261 middleware_name: Some(middleware_name.into()),
262 source: None,
263 }
264 }
265
266 pub fn middleware_error_with_source(
268 msg: impl Into<String>,
269 middleware_name: Option<String>,
270 source: impl std::error::Error + Send + Sync + 'static,
271 ) -> ForgeError {
272 ForgeError::Middleware {
273 message: msg.into(),
274 middleware_name,
275 source: Some(Box::new(source)),
276 }
277 }
278
279 pub fn extension_error(msg: impl Into<String>) -> ForgeError {
281 ForgeError::Extension {
282 message: msg.into(),
283 extension_name: None,
284 source: None,
285 }
286 }
287
288 pub fn extension_error_with_name(
290 msg: impl Into<String>,
291 extension_name: impl Into<String>,
292 ) -> ForgeError {
293 ForgeError::Extension {
294 message: msg.into(),
295 extension_name: Some(extension_name.into()),
296 source: None,
297 }
298 }
299
300 pub fn plugin_error(msg: impl Into<String>) -> ForgeError {
302 extension_error(msg)
303 }
304
305 pub fn transaction_error(msg: impl Into<String>) -> ForgeError {
307 ForgeError::Transaction {
308 message: msg.into(),
309 transaction_id: None,
310 source: None,
311 }
312 }
313
314 pub fn transaction_error_with_id(
316 msg: impl Into<String>,
317 transaction_id: u64,
318 ) -> ForgeError {
319 ForgeError::Transaction {
320 message: msg.into(),
321 transaction_id: Some(transaction_id),
322 source: None,
323 }
324 }
325
326 pub fn history_error(msg: impl Into<String>) -> ForgeError {
328 ForgeError::History {
329 message: msg.into(),
330 source: None,
331 }
332 }
333
334 pub fn config_error(msg: impl Into<String>) -> ForgeError {
336 ForgeError::Config {
337 message: msg.into(),
338 config_key: None,
339 source: None,
340 }
341 }
342
343 pub fn config_error_with_key(
345 msg: impl Into<String>,
346 config_key: impl Into<String>,
347 ) -> ForgeError {
348 ForgeError::Config {
349 message: msg.into(),
350 config_key: Some(config_key.into()),
351 source: None,
352 }
353 }
354
355 pub fn storage_error(msg: impl Into<String>) -> ForgeError {
357 ForgeError::Storage {
358 message: msg.into(),
359 source: None,
360 }
361 }
362
363 pub fn cache_error(msg: impl Into<String>) -> ForgeError {
365 ForgeError::Cache {
366 message: msg.into(),
367 source: None,
368 }
369 }
370
371 pub fn engine_error(msg: impl Into<String>) -> ForgeError {
373 ForgeError::Engine {
374 message: msg.into(),
375 source: None,
376 }
377 }
378
379 pub fn timeout_error(operation: impl Into<String>) -> ForgeError {
381 ForgeError::Timeout {
382 operation: operation.into(),
383 timeout_ms: 0, }
385 }
386
387 pub fn timeout_error_with_duration(operation: impl Into<String>, timeout_ms: u64) -> ForgeError {
389 ForgeError::Timeout {
390 operation: operation.into(),
391 timeout_ms,
392 }
393 }
394
395 pub fn runtime_error(msg: impl Into<String>) -> ForgeError {
397 ForgeError::Engine {
398 message: msg.into(),
399 source: None,
400 }
401 }
402
403 pub fn resource_exhausted_error(resource_type: impl Into<String>) -> ForgeError {
405 ForgeError::ResourceExhausted {
406 resource_type: resource_type.into(),
407 current_usage: None,
408 limit: None,
409 }
410 }
411
412 pub fn resource_exhausted_error_with_usage(
414 resource_type: impl Into<String>,
415 current_usage: usize,
416 limit: usize,
417 ) -> ForgeError {
418 ForgeError::ResourceExhausted {
419 resource_type: resource_type.into(),
420 current_usage: Some(current_usage),
421 limit: Some(limit),
422 }
423 }
424
425 pub fn concurrency_error(msg: impl Into<String>) -> ForgeError {
427 ForgeError::Concurrency {
428 message: msg.into(),
429 source: None,
430 }
431 }
432
433 pub fn validation_error(msg: impl Into<String>) -> ForgeError {
435 ForgeError::Validation {
436 message: msg.into(),
437 field: None,
438 }
439 }
440
441 pub fn validation_error_with_field(
443 msg: impl Into<String>,
444 field: impl Into<String>,
445 ) -> ForgeError {
446 ForgeError::Validation {
447 message: msg.into(),
448 field: Some(field.into()),
449 }
450 }
451
452 pub fn external_dependency_error(
454 dependency: impl Into<String>,
455 source: impl std::error::Error + Send + Sync + 'static,
456 ) -> ForgeError {
457 ForgeError::ExternalDependency {
458 dependency: dependency.into(),
459 source: Box::new(source),
460 }
461 }
462
463 pub fn internal_error(msg: impl Into<String>) -> ForgeError {
465 ForgeError::Internal {
466 message: msg.into(),
467 location: None,
468 }
469 }
470
471 pub fn internal_error_with_location(
473 msg: impl Into<String>,
474 location: impl Into<String>,
475 ) -> ForgeError {
476 ForgeError::Internal {
477 message: msg.into(),
478 location: Some(location.into()),
479 }
480 }
481}
482
483impl From<crate::config::ConfigValidationError> for ForgeError {
485 fn from(err: crate::config::ConfigValidationError) -> Self {
486 ForgeError::Validation {
487 field: Some("config".to_string()),
488 message: err.to_string(),
489 }
490 }
491}