use thiserror::Error;
#[derive(Error, Debug)]
pub enum ForgeError {
#[error("状态错误: {message}")]
State {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("事件错误: {message}")]
Event {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("中间件错误: {message}")]
Middleware {
message: String,
middleware_name: Option<String>,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("扩展错误: {message}")]
Extension {
message: String,
extension_name: Option<String>,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("事务错误: {message}")]
Transaction {
message: String,
transaction_id: Option<u64>,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("历史记录错误: {message}")]
History {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("配置错误: {message}")]
Config {
message: String,
config_key: Option<String>,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("存储错误: {message}")]
Storage {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("缓存错误: {message}")]
Cache {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("引擎错误: {message}")]
Engine {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("操作超时: {operation} (超时时间: {timeout_ms}ms)")]
Timeout { operation: String, timeout_ms: u64 },
#[error("资源不足: {resource_type}")]
ResourceExhausted {
resource_type: String,
current_usage: Option<usize>,
limit: Option<usize>,
},
#[error("并发错误: {message}")]
Concurrency {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("验证失败: {message}")]
Validation { message: String, field: Option<String> },
#[error("外部依赖错误: {dependency}")]
ExternalDependency {
dependency: String,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("内部错误: {message}")]
Internal { message: String, location: Option<String> },
#[error("其他错误: {0}")]
Other(#[from] anyhow::Error),
}
pub type ForgeResult<T> = Result<T, ForgeError>;
impl ForgeError {
pub fn error_code(&self) -> &'static str {
match self {
ForgeError::State { .. } => "STATE_ERROR",
ForgeError::Event { .. } => "EVENT_ERROR",
ForgeError::Middleware { .. } => "MIDDLEWARE_ERROR",
ForgeError::Extension { .. } => "EXTENSION_ERROR",
ForgeError::Transaction { .. } => "TRANSACTION_ERROR",
ForgeError::History { .. } => "HISTORY_ERROR",
ForgeError::Config { .. } => "CONFIG_ERROR",
ForgeError::Storage { .. } => "STORAGE_ERROR",
ForgeError::Cache { .. } => "CACHE_ERROR",
ForgeError::Engine { .. } => "ENGINE_ERROR",
ForgeError::Timeout { .. } => "TIMEOUT_ERROR",
ForgeError::ResourceExhausted { .. } => "RESOURCE_EXHAUSTED",
ForgeError::Concurrency { .. } => "CONCURRENCY_ERROR",
ForgeError::Validation { .. } => "VALIDATION_ERROR",
ForgeError::ExternalDependency { .. } => {
"EXTERNAL_DEPENDENCY_ERROR"
},
ForgeError::Internal { .. } => "INTERNAL_ERROR",
ForgeError::Other(_) => "OTHER_ERROR",
}
}
pub fn is_retryable(&self) -> bool {
matches!(
self,
ForgeError::Timeout { .. }
| ForgeError::ResourceExhausted { .. }
| ForgeError::Concurrency { .. }
| ForgeError::ExternalDependency { .. }
)
}
pub fn is_temporary(&self) -> bool {
matches!(
self,
ForgeError::Timeout { .. }
| ForgeError::ResourceExhausted { .. }
| ForgeError::Concurrency { .. }
)
}
}
pub mod error_utils {
use super::*;
pub fn map_error<T, E: std::error::Error + Send + Sync + 'static>(
result: Result<T, E>,
context: &str,
) -> ForgeResult<T> {
result.map_err(|e| {
ForgeError::Other(anyhow::anyhow!("{}: {}", context, e))
})
}
pub fn state_error(msg: impl Into<String>) -> ForgeError {
ForgeError::State { message: msg.into(), source: None }
}
pub fn state_error_with_source(
msg: impl Into<String>,
source: impl std::error::Error + Send + Sync + 'static,
) -> ForgeError {
ForgeError::State {
message: msg.into(),
source: Some(Box::new(source)),
}
}
pub fn event_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Event { message: msg.into(), source: None }
}
pub fn event_error_with_source(
msg: impl Into<String>,
source: impl std::error::Error + Send + Sync + 'static,
) -> ForgeError {
ForgeError::Event {
message: msg.into(),
source: Some(Box::new(source)),
}
}
pub fn middleware_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Middleware {
message: msg.into(),
middleware_name: None,
source: None,
}
}
pub fn middleware_error_with_name(
msg: impl Into<String>,
middleware_name: impl Into<String>,
) -> ForgeError {
ForgeError::Middleware {
message: msg.into(),
middleware_name: Some(middleware_name.into()),
source: None,
}
}
pub fn middleware_error_with_source(
msg: impl Into<String>,
middleware_name: Option<String>,
source: impl std::error::Error + Send + Sync + 'static,
) -> ForgeError {
ForgeError::Middleware {
message: msg.into(),
middleware_name,
source: Some(Box::new(source)),
}
}
pub fn extension_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Extension {
message: msg.into(),
extension_name: None,
source: None,
}
}
pub fn extension_error_with_name(
msg: impl Into<String>,
extension_name: impl Into<String>,
) -> ForgeError {
ForgeError::Extension {
message: msg.into(),
extension_name: Some(extension_name.into()),
source: None,
}
}
pub fn plugin_error(msg: impl Into<String>) -> ForgeError {
extension_error(msg)
}
pub fn transaction_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Transaction {
message: msg.into(),
transaction_id: None,
source: None,
}
}
pub fn transaction_error_with_id(
msg: impl Into<String>,
transaction_id: u64,
) -> ForgeError {
ForgeError::Transaction {
message: msg.into(),
transaction_id: Some(transaction_id),
source: None,
}
}
pub fn history_error(msg: impl Into<String>) -> ForgeError {
ForgeError::History { message: msg.into(), source: None }
}
pub fn config_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Config {
message: msg.into(),
config_key: None,
source: None,
}
}
pub fn config_error_with_key(
msg: impl Into<String>,
config_key: impl Into<String>,
) -> ForgeError {
ForgeError::Config {
message: msg.into(),
config_key: Some(config_key.into()),
source: None,
}
}
pub fn storage_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Storage { message: msg.into(), source: None }
}
pub fn cache_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Cache { message: msg.into(), source: None }
}
pub fn engine_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Engine { message: msg.into(), source: None }
}
pub fn timeout_error(operation: impl Into<String>) -> ForgeError {
ForgeError::Timeout {
operation: operation.into(),
timeout_ms: 0, }
}
pub fn timeout_error_with_duration(
operation: impl Into<String>,
timeout_ms: u64,
) -> ForgeError {
ForgeError::Timeout { operation: operation.into(), timeout_ms }
}
pub fn runtime_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Engine { message: msg.into(), source: None }
}
pub fn resource_exhausted_error(
resource_type: impl Into<String>
) -> ForgeError {
ForgeError::ResourceExhausted {
resource_type: resource_type.into(),
current_usage: None,
limit: None,
}
}
pub fn resource_exhausted_error_with_usage(
resource_type: impl Into<String>,
current_usage: usize,
limit: usize,
) -> ForgeError {
ForgeError::ResourceExhausted {
resource_type: resource_type.into(),
current_usage: Some(current_usage),
limit: Some(limit),
}
}
pub fn concurrency_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Concurrency { message: msg.into(), source: None }
}
pub fn validation_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Validation { message: msg.into(), field: None }
}
pub fn validation_error_with_field(
msg: impl Into<String>,
field: impl Into<String>,
) -> ForgeError {
ForgeError::Validation {
message: msg.into(),
field: Some(field.into()),
}
}
pub fn external_dependency_error(
dependency: impl Into<String>,
source: impl std::error::Error + Send + Sync + 'static,
) -> ForgeError {
ForgeError::ExternalDependency {
dependency: dependency.into(),
source: Box::new(source),
}
}
pub fn internal_error(msg: impl Into<String>) -> ForgeError {
ForgeError::Internal { message: msg.into(), location: None }
}
pub fn internal_error_with_location(
msg: impl Into<String>,
location: impl Into<String>,
) -> ForgeError {
ForgeError::Internal {
message: msg.into(),
location: Some(location.into()),
}
}
}
impl From<crate::config::ConfigValidationError> for ForgeError {
fn from(err: crate::config::ConfigValidationError) -> Self {
ForgeError::Validation {
field: Some("config".to_string()),
message: err.to_string(),
}
}
}