npx skills add https://github.com/zhanghandong/rust-skills --skill m13-domain-error第二层:设计选择
谁需要处理这个错误,以及他们应该如何恢复?
在设计错误类型之前:
| 错误类型 | 受众 | 恢复方式 | 示例 |
|---|---|---|---|
| 面向用户 | 最终用户 | 引导操作 | InvalidEmail, NotFound |
| 内部错误 | 开发者 | 调试信息 | DatabaseError, |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
ParseError| 系统错误 | 运维/SRE | 监控/告警 | ConnectionTimeout, RateLimited |
| 瞬时错误 | 自动化程序 | 重试 | NetworkError, ServiceUnavailable |
| 永久错误 | 人工处理 | 调查 | ConfigInvalid, DataCorrupted |
在设计错误类型之前:
谁会看到这个错误?
我们能恢复吗?
需要什么上下文?
追溯至领域约束(第三层):
"我应该如何处理支付失败?"
↑ 询问:业务规则对于重试有何要求?
↑ 检查:domain-fintech(交易要求)
↑ 检查:SLA(可用性要求)
| 问题 | 追溯至 | 询问 |
|---|---|---|
| 重试策略 | domain-* | 可接受的重试延迟是多少? |
| 用户体验 | domain-* | 用户应该看到什么消息? |
| 合规性 | domain-* | 审计必须记录什么? |
追溯至实现(第一层):
"需要类型化错误"
↓ m06-error-handling: 库使用 thiserror
↓ m04-zero-cost: 错误枚举设计
"需要错误上下文"
↓ m06-error-handling: anyhow::Context
↓ 日志记录:带字段的 tracing
"需要重试逻辑"
↓ m07-concurrency: 异步重试模式
↓ 依赖包:tokio-retry, backoff
| 恢复模式 | 适用场景 | 实现方式 |
|---|---|---|
| 重试 | 瞬时故障 | 指数退避 |
| 回退 | 降级模式 | 缓存值/默认值 |
| 熔断器 | 级联故障 | failsafe-rs |
| 超时 | 慢操作 | tokio::time::timeout |
| 舱壁隔离 | 隔离 | 独立的线程池 |
#[derive(thiserror::Error, Debug)]
pub enum AppError {
// 面向用户
#[error("Invalid input: {0}")]
Validation(String),
// 瞬时错误(可重试)
#[error("Service temporarily unavailable")]
ServiceUnavailable(#[source] reqwest::Error),
// 内部错误(记录详细信息,显示通用信息)
#[error("Internal error")]
Internal(#[source] anyhow::Error),
}
impl AppError {
pub fn is_retryable(&self) -> bool {
matches!(self, Self::ServiceUnavailable(_))
}
}
use tokio_retry::{Retry, strategy::ExponentialBackoff};
async fn with_retry<F, T, E>(f: F) -> Result<T, E>
where
F: Fn() -> impl Future<Output = Result<T, E>>,
E: std::fmt::Debug,
{
let strategy = ExponentialBackoff::from_millis(100)
.max_delay(Duration::from_secs(10))
.take(5);
Retry::spawn(strategy, || f()).await
}
| 错误做法 | 为何错误 | 更好的做法 |
|---|---|---|
| 所有错误都一样 | 不可操作 | 按受众分类 |
| 重试所有错误 | 浪费资源 | 仅重试瞬时错误 |
| 无限重试 | 导致自我拒绝服务 | 最大尝试次数 + 退避 |
| 暴露内部错误 | 安全风险 | 用户友好的消息 |
| 没有上下文 | 难以调试 | 处处使用 .context() |
| 反面模式 | 为何不好 | 更好的做法 |
|---|---|---|
| 字符串错误 | 没有结构 | thiserror 类型 |
| 对可恢复错误使用 panic! | 用户体验差 | 带上下文的 Result |
| 忽略错误 | 静默失败 | 记录或传播错误 |
| 处处使用 Box | 丢失类型信息 | thiserror |
| 在正常路径中处理错误 | 性能问题 | 尽早验证 |
| 何时使用 | 参见 |
|---|---|
| 错误处理基础 | m06-error-handling |
| 重试实现 | m07-concurrency |
| 领域建模 | m09-domain |
| 面向用户的 API | domain-* |
每周安装量
580
代码仓库
GitHub 星标数
912
首次出现
Jan 20, 2026
安全审计
安装于
opencode533
codex518
gemini-cli508
github-copilot495
amp452
kimi-cli447
Layer 2: Design Choices
Who needs to handle this error, and how should they recover?
Before designing error types:
| Error Type | Audience | Recovery | Example |
|---|---|---|---|
| User-facing | End users | Guide action | InvalidEmail, NotFound |
| Internal | Developers | Debug info | DatabaseError, ParseError |
| System | Ops/SRE | Monitor/alert | ConnectionTimeout, RateLimited |
| Transient | Automation | Retry | NetworkError, ServiceUnavailable |
| Permanent | Human | Investigate | ConfigInvalid, DataCorrupted |
Before designing error types:
Who sees this error?
Can we recover?
What context is needed?
To domain constraints (Layer 3):
"How should I handle payment failures?"
↑ Ask: What are the business rules for retries?
↑ Check: domain-fintech (transaction requirements)
↑ Check: SLA (availability requirements)
| Question | Trace To | Ask |
|---|---|---|
| Retry policy | domain-* | What's acceptable latency for retry? |
| User experience | domain-* | What message should users see? |
| Compliance | domain-* | What must be logged for audit? |
To implementation (Layer 1):
"Need typed errors"
↓ m06-error-handling: thiserror for library
↓ m04-zero-cost: Error enum design
"Need error context"
↓ m06-error-handling: anyhow::Context
↓ Logging: tracing with fields
"Need retry logic"
↓ m07-concurrency: async retry patterns
↓ Crates: tokio-retry, backoff
| Recovery Pattern | When | Implementation |
|---|---|---|
| Retry | Transient failures | exponential backoff |
| Fallback | Degraded mode | cached/default value |
| Circuit Breaker | Cascading failures | failsafe-rs |
| Timeout | Slow operations | tokio::time::timeout |
| Bulkhead | Isolation | separate thread pools |
#[derive(thiserror::Error, Debug)]
pub enum AppError {
// User-facing
#[error("Invalid input: {0}")]
Validation(String),
// Transient (retryable)
#[error("Service temporarily unavailable")]
ServiceUnavailable(#[source] reqwest::Error),
// Internal (log details, show generic)
#[error("Internal error")]
Internal(#[source] anyhow::Error),
}
impl AppError {
pub fn is_retryable(&self) -> bool {
matches!(self, Self::ServiceUnavailable(_))
}
}
use tokio_retry::{Retry, strategy::ExponentialBackoff};
async fn with_retry<F, T, E>(f: F) -> Result<T, E>
where
F: Fn() -> impl Future<Output = Result<T, E>>,
E: std::fmt::Debug,
{
let strategy = ExponentialBackoff::from_millis(100)
.max_delay(Duration::from_secs(10))
.take(5);
Retry::spawn(strategy, || f()).await
}
| Mistake | Why Wrong | Better |
|---|---|---|
| Same error for all | No actionability | Categorize by audience |
| Retry everything | Wasted resources | Only transient errors |
| Infinite retry | DoS self | Max attempts + backoff |
| Expose internal errors | Security risk | User-friendly messages |
| No context | Hard to debug | .context() everywhere |
| Anti-Pattern | Why Bad | Better |
|---|---|---|
| String errors | No structure | thiserror types |
| panic! for recoverable | Bad UX | Result with context |
| Ignore errors | Silent failures | Log or propagate |
| Box everywhere | Lost type info | thiserror |
| Error in happy path | Performance | Early validation |
| When | See |
|---|---|
| Error handling basics | m06-error-handling |
| Retry implementation | m07-concurrency |
| Domain modeling | m09-domain |
| User-facing APIs | domain-* |
Weekly Installs
580
Repository
GitHub Stars
912
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode533
codex518
gemini-cli508
github-copilot495
amp452
kimi-cli447
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
103,800 周安装
OpenAPI 转 TypeScript 工具 - 自动生成 API 接口与类型守卫
563 周安装
数据库模式设计器 - 内置最佳实践,自动生成生产级SQL/NoSQL数据库架构
564 周安装
Rust Unsafe代码检查器 - 安全使用Unsafe Rust的完整指南与最佳实践
564 周安装
.NET并发编程模式指南:async/await、Channels、Akka.NET选择决策树
565 周安装
韩语语法检查器 - 基于国立国语院标准的拼写、空格、语法、标点错误检测与纠正
565 周安装
技能安全扫描器 - 检测Claude技能安全漏洞,防范提示注入与恶意代码
565 周安装