15 KiB
错误处理
**本文档中引用的文件** - [app_error.rs](file://crates/shared_types/src/model/app_error.rs) - [http_result.rs](file://crates/shared_types/src/model/http_result.rs) - [tracing_middleware.rs](file://crates/agent_runner/src/middleware/tracing_middleware.rs) - [tracing_middleware.rs](file://crates/rcoder/src/middleware/tracing_middleware.rs) - [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs) - [agent_cancel_handler.rs](file://crates/agent_runner/src/handler/agent_cancel_handler.rs) - [lib.rs](file://crates/shared_types/src/lib.rs)目录
简介
本文档全面解释系统中的错误处理机制,重点描述在 tracing_middleware_handler 中如何捕获和处理HTTP中间件错误,包括 Result<Response, StatusCode> 的返回模式。结合 shared_types 中的 AppError 模型,说明应用级错误的结构设计和序列化方式。文档包括来自实际代码库的具体示例,如中间件中错误的传播和日志记录,以及错误处理与可观测性的集成。
核心错误类型
系统采用分层错误处理架构,主要包含两种核心错误类型:AppError 和 HttpResult。AppError 作为应用级错误的统一抽象,封装了不同来源的错误,而 HttpResult 则是标准化的HTTP响应格式,用于向客户端返回一致的错误信息。
classDiagram
class AppError {
+AnyhowError(anyhow : : Error)
+IoError(std : : io : : Error)
+Generic(String)
+generic(msg : impl Into<String>) AppError
+internal_server_error(msg : &str) AppError
+validation_error(msg : &str) AppError
}
class HttpResult~T~ {
+code : String
+message : String
+data : Option~T~
+tid : Option~String~
+success : bool
+success(data : T) HttpResult~T~
+error(code : &str, message : &str) HttpResult~T~
+internal_error(message : &str) HttpResult~T~
}
AppError --> "implements" axum : : response : : IntoResponse
HttpResult~T~ --> "implements" axum : : response : : IntoResponse
HttpResult~T~ --> "serializes to" JSON
图源
本节源
HTTP中间件错误处理
tracing_middleware_handler 是系统中的核心HTTP中间件,负责请求追踪和错误处理。该中间件采用 Result<Response, StatusCode> 的返回模式,确保所有HTTP请求都能被正确处理或以适当的HTTP状态码返回错误。
中间件的主要功能包括:
- 为每个HTTP请求自动生成
trace_id - 创建请求span用于日志跟踪
- 记录请求和响应信息
- 自动将
trace_id注入到OpenTelemetry上下文中
sequenceDiagram
participant Client as "客户端"
participant Middleware as "tracing_middleware_handler"
participant Next as "下一个处理器"
participant Response as "响应"
Client->>Middleware : HTTP请求
Middleware->>Middleware : 提取或生成trace_id
Middleware->>Middleware : 创建追踪span
Middleware->>Middleware : 记录请求开始日志
Middleware->>Next : 调用next.run()
Next-->>Middleware : 返回Response
Middleware->>Middleware : 记录响应完成日志
Middleware->>Response : 返回Result<Response, StatusCode>
Response-->>Client : HTTP响应
图源
本节源
应用级错误结构
AppError 枚举是系统中应用级错误的核心数据结构,定义了三种主要的错误类型:
- AnyhowError: 包装
anyhow::Error类型,用于处理任意错误 - IoError: 包装标准库的
std::io::Error,用于处理I/O操作错误 - Generic: 通用错误类型,用于表示自定义错误消息
AppError 实现了 axum::response::IntoResponse trait,使其可以直接作为HTTP响应返回。当错误发生时,系统会根据错误类型映射到相应的HTTP状态码,并生成结构化的JSON响应。
flowchart TD
Start([错误发生]) --> MatchError["匹配AppError类型"]
MatchError --> AnyhowError{"是AnyhowError?"}
AnyhowError --> |是| Set500["设置状态码500"]
MatchError --> IoError{"是IoError?"}
IoError --> |是| Set500
MatchError --> Generic{"是Generic?"}
Generic --> |是| Set500
Set500 --> CreateJSON["创建JSON响应体"]
CreateJSON --> ReturnResponse["返回Response"]
ReturnResponse --> End([错误响应完成])
图源
本节源
错误传播与日志记录
系统中的错误传播遵循Rust的错误处理最佳实践,使用 ? 操作符进行错误传播,并在适当的位置使用 map_err 进行错误转换。这种模式确保了错误信息能够在调用栈中正确传递,同时保持代码的简洁性。
在日志记录方面,系统使用 tracing 库进行结构化日志记录。每个错误都会被记录为包含 trace_id 的结构化日志条目,便于后续的错误追踪和分析。
// 示例:错误传播和日志记录
let project_workspace = get_project_workspace(&project_id).await?;
// 示例:错误转换
.map_err(|e| anyhow::anyhow!(e))?;
// 示例:错误日志记录
error!(
"❌ 收到 agent 执行结果失败: {}",
e
);
本节源
错误分类与状态码映射
系统采用统一的错误分类和状态码映射策略,确保错误处理的一致性。错误分类主要基于错误的严重程度和来源:
- 客户端错误 (4xx): 由客户端请求引起的错误,如参数验证失败
- 服务器错误 (5xx): 由服务器内部问题引起的错误,如数据库连接失败
- 业务逻辑错误: 特定于业务场景的错误,使用自定义错误码
状态码映射遵循HTTP标准,同时使用自定义错误码提供更详细的错误信息。例如,5000 表示内部服务器错误,9010 表示Agent正在执行任务等。
erDiagram
ERROR_CATEGORY {
string code PK
string name
string description
int http_status
string severity
}
ERROR_CODE {
string code PK
string category FK
string message
string solution
datetime created_at
}
ERROR_CATEGORY ||--o{ ERROR_CODE : contains
ERROR_CATEGORY {
"CLIENT_ERROR" "客户端错误" "请求参数错误等" 400 "HIGH"
"SERVER_ERROR" "服务器错误" "内部服务错误" 500 "CRITICAL"
"BUSINESS_ERROR" "业务错误" "业务逻辑错误" 400 "MEDIUM"
}
ERROR_CODE {
"0001" "BUSINESS_ERROR" "停止智能体执行失败" "重试或联系管理员" "2024-01-01"
"5000" "SERVER_ERROR" "内部服务器错误" "检查服务日志" "2024-01-01"
"9010" "BUSINESS_ERROR" "Agent正在执行任务" "等待当前任务完成" "2024-01-01"
"PROMPT001" "SERVER_ERROR" "Agent处理失败" "检查Agent状态" "2024-01-01"
}
图源
本节源
错误信息暴露策略
系统采用谨慎的错误信息暴露策略,平衡了调试需求和安全考虑。错误信息暴露遵循以下原则:
- 生产环境最小化暴露: 在生产环境中,只暴露必要的错误信息,避免泄露敏感信息
- 开发环境详细暴露: 在开发环境中,提供详细的错误信息,便于调试
- 结构化错误响应: 所有错误都以统一的JSON格式返回,包含错误码、消息和trace_id
HttpResult 结构的设计体现了这一策略,它包含 code、message、data、tid 和 success 字段,确保客户端能够获得足够的信息来处理错误,同时不会暴露过多的内部细节。
stateDiagram-v2
[*] --> Production
[*] --> Development
Production --> ErrorHandling : 发生错误
Development --> ErrorHandling : 发生错误
ErrorHandling --> CheckEnvironment : 检查环境
CheckEnvironment --> |生产环境| MinimizeInfo : 最小化错误信息
CheckEnvironment --> |开发环境| DetailedInfo : 详细错误信息
MinimizeInfo --> FormatResponse : 格式化为标准响应
DetailedInfo --> FormatResponse : 格式化为标准响应
FormatResponse --> LogError : 记录完整错误日志
LogError --> ReturnResponse : 返回响应
ReturnResponse --> [*]
图源
本节源
可观测性集成
错误处理与系统的可观测性深度集成,主要体现在以下几个方面:
- 分布式追踪: 每个请求都分配唯一的
trace_id,贯穿整个请求处理链路 - 结构化日志: 所有错误日志都包含
trace_id,便于跨服务追踪 - 指标监控: 错误发生时记录相应的指标,用于监控和告警
trace_id 的生成和传播机制确保了在复杂的微服务架构中,能够快速定位和诊断问题。系统优先从请求头中提取 trace_id,如果不存在则生成新的UUID作为 trace_id。
graph TD
A[客户端请求] --> B{包含trace_id?}
B --> |是| C[使用请求中的trace_id]
B --> |否| D[生成新的trace_id]
C --> E[注入到OpenTelemetry上下文]
D --> E
E --> F[记录带trace_id的日志]
F --> G[传播到下游服务]
G --> H[集中式日志系统]
H --> I[错误分析和根因定位]
图源
本节源
常见问题与解决方案
在实际使用中,可能会遇到一些常见的错误处理问题,以下是这些问题及其解决方案:
错误信息泄露
问题: 生产环境中暴露了过多的内部错误细节,可能导致安全风险。 解决方案: 实现环境感知的错误响应策略,在生产环境中只返回通用的错误消息,详细的错误信息仅在开发环境中暴露。
错误码不一致
问题: 不同的处理器使用不同的错误码,导致客户端难以处理。 解决方案: 建立统一的错误码注册表,所有错误码都从中心化的位置获取,确保一致性。
trace_id丢失
问题: 在某些异步操作中,trace_id 可能丢失,导致无法完整追踪请求链路。
解决方案: 在 HttpResult 的 into_response 实现中添加 trace_id 的补全逻辑,确保即使在中间件之外创建的响应也能包含 trace_id。
flowchart TD
A[问题识别] --> B[错误信息泄露]
A --> C[错误码不一致]
A --> D[trace_id丢失]
B --> E[实施环境感知响应]
C --> F[建立错误码注册表]
D --> G[实现trace_id补全]
E --> H[解决方案]
F --> H
G --> H
H --> I[改进的错误处理]
图源
本节源
错误处理流程图
以下是系统错误处理的完整流程图,展示了从错误发生到最终响应的整个过程:
flowchart TD
A[HTTP请求] --> B[tracing_middleware]
B --> C[提取/生成trace_id]
C --> D[创建追踪span]
D --> E[调用业务处理器]
E --> F{发生错误?}
F --> |是| G[捕获错误]
F --> |否| H[返回成功响应]
G --> I[转换为AppError]
I --> J[记录错误日志]
J --> K[创建HttpResult错误响应]
K --> L[序列化为JSON]
L --> M[返回HTTP错误响应]
H --> N[创建HttpResult成功响应]
N --> O[序列化为JSON]
O --> P[返回HTTP成功响应]
M --> Q[客户端]
P --> Q
style F fill:#f9f,stroke:#333,stroke-width:2px
style G fill:#f96,stroke:#333,stroke-width:2px
style H fill:#6f9,stroke:#333,stroke-width:2px
图源
本节源
监控与告警最佳实践
为了有效监控和告警系统中的错误,建议采用以下最佳实践:
- 基于trace_id的根因分析: 利用
trace_id作为关键字,在日志系统中搜索完整的请求链路,快速定位问题根源。 - 错误率监控: 监控不同错误码的发生频率,设置告警阈值。
- P99延迟监控: 监控错误响应的P99延迟,确保错误处理不会成为性能瓶颈。
- 错误分类仪表板: 创建按错误类型、服务、时间维度分类的仪表板,便于趋势分析。
通过这些实践,可以建立一个健壮的错误监控体系,及时发现和解决系统中的问题。
本节源