feat(ai): 扩展 AiError 支持配额/缓存/知识库/队列/配置错误变体
新增 QuotaExhausted→429, CacheError/KnowledgeError/QueueError/ConfigError→500
This commit is contained in:
@@ -31,6 +31,21 @@ pub enum AiError {
|
||||
|
||||
#[error("数据库错误: {0}")]
|
||||
DbError(String),
|
||||
|
||||
#[error("AI 配额已耗尽: {reason}")]
|
||||
QuotaExhausted { tenant_id: uuid::Uuid, reason: String },
|
||||
|
||||
#[error("缓存错误: {0}")]
|
||||
CacheError(String),
|
||||
|
||||
#[error("知识库错误: {0}")]
|
||||
KnowledgeError(String),
|
||||
|
||||
#[error("分析队列错误: {0}")]
|
||||
QueueError(String),
|
||||
|
||||
#[error("AI 配置错误: {0}")]
|
||||
ConfigError(String),
|
||||
}
|
||||
|
||||
impl From<AiError> for AppError {
|
||||
@@ -43,6 +58,7 @@ impl From<AiError> for AppError {
|
||||
AppError::Internal(format!("AI 提供商 {p} 不可用"))
|
||||
}
|
||||
AiError::RateLimitExceeded => AppError::TooManyRequests,
|
||||
AiError::QuotaExhausted { .. } => AppError::TooManyRequests,
|
||||
AiError::VersionMismatch => AppError::VersionMismatch,
|
||||
AiError::DbError(msg) => AppError::Internal(msg),
|
||||
other => AppError::Internal(other.to_string()),
|
||||
@@ -161,4 +177,54 @@ mod tests {
|
||||
other => panic!("期望 AppError::Internal,得到 {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quota_exhausted_maps_to_429() {
|
||||
let err = AiError::QuotaExhausted {
|
||||
tenant_id: uuid::Uuid::now_v7(),
|
||||
reason: "monthly budget".into(),
|
||||
};
|
||||
let app: AppError = err.into();
|
||||
assert!(matches!(app, AppError::TooManyRequests));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cache_error_maps_to_internal() {
|
||||
let err = AiError::CacheError("redis timeout".into());
|
||||
let app: AppError = err.into();
|
||||
match app {
|
||||
AppError::Internal(msg) => assert!(msg.contains("redis timeout")),
|
||||
other => panic!("期望 AppError::Internal,得到 {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn knowledge_error_maps_to_internal() {
|
||||
let err = AiError::KnowledgeError("rule not found".into());
|
||||
let app: AppError = err.into();
|
||||
match app {
|
||||
AppError::Internal(msg) => assert!(msg.contains("rule not found")),
|
||||
other => panic!("期望 AppError::Internal,得到 {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn queue_error_maps_to_internal() {
|
||||
let err = AiError::QueueError("queue full".into());
|
||||
let app: AppError = err.into();
|
||||
match app {
|
||||
AppError::Internal(msg) => assert!(msg.contains("queue full")),
|
||||
other => panic!("期望 AppError::Internal,得到 {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_error_maps_to_internal() {
|
||||
let err = AiError::ConfigError("missing provider".into());
|
||||
let app: AppError = err.into();
|
||||
match app {
|
||||
AppError::Internal(msg) => assert!(msg.contains("missing provider")),
|
||||
other => panic!("期望 AppError::Internal,得到 {:?}", other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user