错误处理升级前的核对项

Rust 项目从字符串错误迁移到枚举错误,或从通用错误容器改成分层错误类型,看起来只是整理返回值,实际上会影响公共 API、日志、重试策略和监控分类。升级做得不好,代码可能更“类型安全”了,排障信息却更少;调用方也可能因为错误变体变化,做出和旧版本不同的处理。
先画出错误流向
从最底层依赖开始,列出错误经过哪些模块,最终由谁消费。库代码通常需要保留机器可判断的类型,让调用方区分无效输入、资源不存在、权限不足和临时依赖故障。应用边界则需要把内部错误转换成 HTTP 状态、命令行退出码或用户提示。两层目标不同,不宜用同一种字符串一路传到底。
升级前要搜索所有 map_err、unwrap、expect、通用 Box<dyn Error> 和日志点,确认现有调用方依赖了什么。有些代码会匹配错误文本来决定重试,这种做法本身脆弱,却是迁移必须处理的现实兼容点。先补测试固定当前行为,再改调用方式,避免错误消息稍微调整就让某个后台任务停止重试。
错误类型要保留原因与上下文
错误枚举应按调用方需要采取的动作划分,而不是照着每个内部函数各造一个变体。底层错误可以作为 source 保留,便于打印完整原因链;在边界处补充资源标识、操作名称和阶段信息。上下文要帮助定位,但不能把令牌、完整请求体或个人信息塞进错误文本。
使用 From 自动转换很方便,不过过宽的转换会丢失语义。两个不同阶段都可能返回同一种 I/O 错误,一个是读取配置,一个是写入结果,调用方的处理方式可能不同。评审时应检查每个 ? 最终映射到哪个公共变体,必要时在转换处明确阶段,而不是把所有 I/O 问题都归成 Internal。
公开错误枚举还涉及兼容性。下游可能穷举匹配现有变体,新增变体就会要求重新处理。库应根据自己的版本策略决定是否允许穷举,并在文档中说明哪些分类稳定、哪些细节只用于诊断。错误文案通常不应成为稳定接口,稳定的是错误类别、字段和是否可重试。
日志只在能够处理的边界记录
同一个错误如果在底层、服务层和入口各打印一次,会形成三条看似不同的告警。更清楚的做法是让错误向上传递,在真正决定重试、降级或返回用户的边界记录一次,并带上请求标识与原因链。低层只有在吞掉错误、改变控制流或需要补充现场时才单独记录。
监控分类也要跟着迁移。旧看板若按错误字符串聚合,类型升级后可能突然失去数据。发布前建立新旧分类的映射,灰度期间同时观察总错误数、各类别占比、重试量和最终失败。日志字段名与告警规则同步更新,不要等到事故时才发现搜索条件已经过期。
把失败路径跑一遍
基础检查仍然要覆盖整个工作区:
cargo check --workspace && cargo test --workspace
在此之外,还要主动制造配置缺失、权限拒绝、依赖超时、响应格式错误、任务取消和磁盘写入失败。每个样例都核对返回类型、原因链、用户可见信息、日志次数以及重试决定。若迁移包含 unwrap 清理,要确认原先会崩溃的路径如今返回错误后,调用方真的能收口,而不是在更远处以另一种方式失败。
灰度发布时按版本拆分错误指标,抽查新旧版本对同一失败输入的分类是否一致。回退也要验证:错误类型只存在进程内通常容易回退,但若任务状态或消息队列中持久化了错误码,旧版本必须能够识别。
错误处理升级的完成标准不是“全项目统一用了某个库”,而是调用方能稳定判断,日志能还原原因,监控能看见变化,敏感信息没有外泄。类型只是载体,真正需要升级的是失败发生后整条链路的行为。

160

被折叠的 条评论
为什么被折叠?



