测试云原生质量保障【免费下载链接】originConformance test suite for OpenShift项目地址https://gitcode.com/gh_mirrors/or/origin点击查看免费下载导读errdefs 是 containerd 的一个 Go 子项目为所有 containerd 相关服务提供了一套统一的错误类型定义与检测机制。本仓库OpenShift 一致性测试套件 origin以 vendored 依赖形式引入该包vendor/modules.txterrdefs v1.0.0与errdefs/pkg v0.3.0用于在分布式、容器化的错误处理链路中保持语义一致。读完本文你将掌握 errdefs 的 16 种错误类、Is*检测函数、Resolve解析逻辑以及 errgrpc / errhttp 两个子包如何把错误无缝映射为 gRPC Code 与 HTTP 状态码。一、errdefs 是什么根据 READMEerrdefs 的定位非常简洁A Go package for defining and checking common containerd errors.即“一个用于定义和检测containerd 公共错误的 Go 包”。它是 containerd 的官方子项目遵循 Apache 2.0 许可见 LICENSE其治理、维护者与贡献指南均由上层containerd/project仓库统一管理。从源码看这个包的核心设计目标在 errors.go 的包注释中写得很清楚定义 containerd 各包共用的错误类通过fmt.Errorf包装错误以附加上下文通过IsXXX系列函数判断一个错误是否属于某个错误类。这套错误类与 gRPC 错误码高度对应最终目的是让服务端能够根据错误类别引导客户端采取正确的动作重试、改参数、查询资源等。二、16 个预定义错误类及其语义errors.go 以包级var一次性声明了全部错误类的哨兵值sentinel values每个错误类都是独立的空结构体类型通过Error()返回固定描述哨兵值错误描述语义对应 gRPC CodeErrUnknownunknown未知、未处理或意外响应UnknownErrInvalidArgumentinvalid argument参数不合法InvalidArgumentErrNotFoundnot found对象缺失NotFoundErrAlreadyExistsalready exists元数据已存在AlreadyExistsErrPermissionDeniedpermission denied无权限403PermissionDeniedErrResourceExhaustedresource exhausted资源不足或尝试过多ResourceExhaustedErrFailedPreconditionfailed precondition前置条件不满足FailedPreconditionErrConflictconflict操作冲突FailedPrecondition见下ErrNotModifiednot modified对象与先前状态一致FailedPrecondition见下ErrAbortedaborted操作被中止AbortedErrOutOfRangeout of range数据超出预期范围OutOfRangeErrNotImplementednot implemented功能未实现UnimplementedErrInternalinternal内部/系统错误InternalErrUnavailableunavailable资源不可用UnavailableErrDataLossdata loss数据丢失或损坏DataLossErrUnauthenticatedunauthorized未认证/未授权Unauthenticated每个错误类型都实现了两个东西Error() string与一个标记方法如errNotFound.NotFound()、errPermissionDenied.Forbidden()。标记方法的存在使错误可以通过 Go 1.18 泛型的接口断言被识别这也是Is*检测的基础。2.1 与 context 错误的关系errdefs 没有单独定义“超时”“取消”两类错误而是直接复用标准库的context.DeadlineExceeded与context.Canceled// IsCanceled returns true if the error is due to context.Canceled. func IsCanceled(err error) bool { return errors.Is(err, context.Canceled) || isInterfacecancelled }对应地errdefs 还定义了cancelled/deadlineExceeded两个接口允许第三方错误实现Cancelled()/DeadlineExceeded()方法从而被IsCanceled/IsDeadlineExceeded识别见 errors.go。这一设计与 Moby 的ErrCancelled、ErrDeadline一一对应源码注释中明确标注了映射关系例如cancelled对应 Moby 的ErrCancelled、unknown对应ErrUnknown。2.2 带自定义消息的错误customMessage直接返回哨兵值只能得到固定描述如not found实际使用中往往需要携带更具体的信息。errdefs 通过WithMessage方法解决func (e errNotFound) WithMessage(msg string) error { return customMessage{e, msg} }customMessageerrors.go是一个内部包装类型Error()返回自定义消息同时实现Is(err error) bool比较底层错误是否等于哨兵值与As(target any) bool委托给errors.As因此包装后的错误仍能被errors.Is/errors.As与原始哨兵值匹配消息内容却完全自定义。这也是包注释中“Use withfmt.Errorfto add context”之外的另一条附加上下文路径。三、Is* 检测函数与错误链遍历errdefs 提供了一整套IsXXX检测函数覆盖上表全部错误类另有IsCanceled、IsDeadlineExceeded两个 context 错误检测。每个函数的结构完全一致以IsNotFound为例// IsNotFound returns true if the error is due to a missing object func IsNotFound(err error) bool { return errors.Is(err, ErrNotFound) || isInterfacenotFound }即两条判定路径errors.Is链式匹配沿Unwrap()错误链查找是否与哨兵值相等兼容fmt.Errorf(%w, ...)包装isInterface[T]泛型接口断言递归检查错误链中是否有一个类型实现了对应标记接口。3.1 isInterface 的遍历逻辑isInterface[T any]errors.go是理解 errdefs 检测能力的核心它在一个for循环中逐层剥开错误链类型断言成功case T:→ 返回true遇到customMessage→ 取其内部err继续遇到实现Unwrap() error的类型 → 沿单一包装链下钻为nil时返回false遇到实现Unwrap() []error的类型即errors.Join产生的多错误→ 对每个子错误递归调用isInterface其他类型 → 返回false。这意味着 errdefs 的检测不仅支持传统%w单链包装也完整支持 Go 1.20 引入的errors.Join多错误合并场景检测结果是“错误链上任意一层命中即算命中”。四、Resolve把错误链归约到首个可识别错误resolve.go 中的Resolve(err error) error提供了一种“取外层可见错误类别”的能力返回错误链中第一个匹配 errdefs 错误类或 context 错误的错误若无匹配则返回原始未包装错误或ErrUnknown。它的典型应用场景在源码注释中有精确描述错误链深处的ErrNotFound可能被包装成invalid argument。当使用Is*系列函数判断时错误深度与顺序不被考虑而Resolve则是从最外层开始找到第一个能归类的错误从而决定响应码。firstErrorresolve.go的具体归约顺序为直接命中 16 个哨兵值或两个 context 错误按类型识别标记接口customMessage、unknown、invalidParameter、notFound、forbidden、system等均映射到对应哨兵值沿Unwrap() error单链下钻对Unwrap() []error的每个子错误深度优先递归——注释明确说明Unwrap() error链中任何位置返回的包装错误都会先于Unwrap() []error的 joined 错误被返回若错误实现了Is(error) bool则依次与全部哨兵值比较均不匹配则返回nil由Resolve兜底为ErrUnknown。五、errgrpc错误与 gRPC Code 的双向翻译pkg/errgrpc/grpc.go 提供ToGRPC/ToNative/ToGRPCf三个函数用于 gRPC 服务端与客户端的错误类型双向映射。5.1 ToGRPC错误 → gRPC statusToGRPC(err error) error先通过status.FromError判断错误是否已经是 gRPC 错误避免重复映射否则调用statusFromError依据errdefs.Resolve的结果生成对应codes.Code的 status。映射关系如下grpc.goerrdefs 错误类gRPC CodeErrInvalidArgumentInvalidArgumentErrNotFoundNotFoundErrAlreadyExistsAlreadyExistsErrPermissionDeniedPermissionDeniedErrResourceExhaustedResourceExhaustedErrFailedPrecondition/ErrConflict/ErrNotModifiedFailedPreconditionErrAbortedAbortedErrOutOfRangeOutOfRangeErrNotImplementedUnimplementedErrInternalInternalErrUnavailableUnavailableErrDataLossDataLossErrUnauthenticatedUnauthenticatedcontext.DeadlineExceededDeadlineExceededcontext.CanceledCanceled其余含ErrUnknownUnknown值得注意ErrConflict、ErrNotModified与ErrFailedPrecondition在 gRPC 侧共享FailedPrecondition码因此反向翻译ToNative时需要借助消息后缀来区分见下文。5.2 错误详情的保留与还原ToGRPC并不满足于只转换状态码还通过errorDetailsgrpc.go尽量把原始错误结构作为 gRPC status 的 details 一起携带。保留能力依赖以下机制接口约定错误若实现WrapError(error) error包装、JoinErrors(...error) error合并或CollapseError()折叠见 collapsible.go则按对应语义重建错误链序列化实现proto.Message/protoadapt.MessageV1的错误直接作为 proto 消息指针类型错误可通过typeurl.MarshalAny打包为anypb.Any依赖github.com/containerd/typeurl/v2。设计意图在源码注释中表述得很明确重新应用这些 details 后Error()、errors.Is、errors.As以及%v格式化输出应与原始错误完全一致。5.3 ToNativegRPC status → 原生错误ToNative(err error)grpc.go是反向操作解析 status 的 code 与 message映射回 errdefs 错误类。两个细节值得注意FailedPrecondition 细分由于ErrConflict/ErrNotModified在 gRPC 侧共享该码ToNative通过检查 message 是否等于或以: 后缀结束于conflict/not modified来还原具体错误类代码注释同时指出该启发式尚不完善计划用正则改进未知 code 兜底默认分支会尝试解析cause.ErrUnexpectedStatus的unexpected status NNN前缀见 cause.go当状态码在 200–599 之间时还原为ErrUnexpectedStatus{Status: N}否则归为ErrUnknown。此外ToNative会遍历 status details依据WrapError/JoinErrors/CollapseError接口重建错误链多个详情用errors.Join合并单个详情则保留首个错误——整体实现了错误在 gRPC 边界上的“无损往返”。ToGRPCf(err, format, args...)则是ToGRPC(fmt.Errorf(format: %w, err))的便捷封装。六、errhttp错误与 HTTP 状态码的双向翻译pkg/errhttp/http.go 提供了面向 HTTP 服务的等价工具ToHTTP(err error) int与ToNative(statusCode int) error。6.1 ToHTTP错误 → 状态码ToHTTP按Is*检测顺序返回最贴切的 HTTP 状态码http.goerrdefs 错误类HTTP 状态码ErrNotFound404 Not FoundErrInvalidArgument400 Bad RequestErrConflict409 ConflictErrNotModified304 Not ModifiedErrFailedPrecondition412 Precondition FailedErrUnauthenticated401 UnauthorizedErrPermissionDenied403 ForbiddenErrResourceExhausted429 Too Many RequestsErrInternal500 Internal Server ErrorErrNotImplemented501 Not ImplementedErrUnavailable503 Service UnavailableErrUnknown500若可解析为ErrUnexpectedStatus且状态码在 200–599则直接返回该状态码这里可以看到与 gRPC 映射的显著差异HTTP 协议拥有更细粒度的状态码ErrConflict409与ErrNotModified304不再与ErrFailedPrecondition412合并ErrResourceExhausted也被映射为 429 而非 gRPC 的 ResourceExhausted。6.2 ToNative状态码 → 错误ToNative(statusCode int)http.go是反向映射404 →ErrNotFound、400 →ErrInvalidArgument、409 →ErrConflict、412 →ErrFailedPrecondition、401 →ErrUnauthenticated、403 →ErrPermissionDenied、304 →ErrNotModified、429 →ErrResourceExhausted、500 →ErrInternal、501 →ErrNotImplemented、503 →ErrUnavailable未识别的状态码则归入cause.ErrUnexpectedStatus{Status: statusCode}保留原始数值以便调用方继续处理。七、errdefs 在本仓库中的角色与最佳实践本仓库OpenShift 一致性测试套件 origin将 errdefs 作为 vendored 第三方依赖引入vendor/modules.txt中记录github.com/containerd/errdefs v1.0.0与github.com/containerd/errdefs/pkg v0.3.0前者导出根包errors.go、resolve.go后者导出errgrpc、errhttp子包。这说明 errdefs 是 OpenShift / containerd 生态中跨组件错误语义统一的基础设施——服务端用Err*哨兵值产出错误经errgrpc.ToGRPC或errhttp.ToHTTP翻译成协议层状态码客户端再用ToNative还原为可编程处理的错误类全程保持errors.Is/errors.As语义。在实际项目中应用 errdefs 时可以遵循以下模式定义错误直接返回哨兵值或用WithMessage/fmt.Errorf(%w, ...)附加上下文检测错误一律使用IsNotFound、IsInvalidArgument等Is*函数而非字符串比较天然兼容包装链与errors.Join边界翻译服务出口处用errgrpc.ToGRPC/errhttp.ToHTTP完成协议转换入口处用ToNative还原利用 Resolve在需要“最外层可见类别”来决定响应码时使用errdefs.Resolve它遵循深度优先的归约规则优先返回单链包装错误而非 joined 错误保留结构自定义错误若需跨 gRPC 无损传输实现WrapError/JoinErrors/CollapseError接口并确保类型可通过 protobuf 或 typeurl 序列化。八、总结errdefs 用一套极简的哨兵值 标记接口设计为 Go 服务提供了与 gRPC / HTTP 协议深度对齐的统一错误分类语言。其核心价值在于错误定义、检测、解析、协议翻译四个环节全部集中于此避免了每个服务各自发明错误码导致的语义碎片化。本文所述全部实现均可直接在 vendor/github.com/containerd/errdefs 目录下阅读验证核心文件包括错误类定义与Is*检测errors.go错误链归约resolve.gogRPC 双向翻译pkg/errgrpc/grpc.goHTTP 双向翻译pkg/errhttp/http.go未知状态码根因pkg/internal/cause/cause.go折叠错误类型pkg/internal/types/collapsible.go赞分享测试云原生质量保障【免费下载链接】originConformance test suite for OpenShift项目地址https://gitcode.com/gh_mirrors/or/origin点击查看免费下载相关推荐Go 错误处理实战深度解析 containerd errdefs 通用错误定义与检测包Go 错误处理实战深度解析 containerd errdefs 通用错误定义与检测包 errdefs 是 containerd 生态中负责统一错误语义的基础人工智能AI AgentAgent 沙箱云原生容器运行时零信任彻底解决Containerd gRPC错误从原理到实战的容错架构设计彻底解决Containerd gRPC错误从原理到实战的容错架构设计 你是否遇到过Containerd客户端连接超时却无法定位原因调用容器API时错误信息模云原生容器运行时Xberg 错误参考跨语言统一错误类型、FFI 稳定错误码与定位实战Xberg 错误参考跨语言统一错误类型、FFI 稳定错误码与定位实战 本篇技术指南以 Xberg 官方文档中的 Error Reference https:/后端AI 应用NLP上一篇BewlyBewly 贡献指南开发环境搭建、构建打包与分支 Commit 规范详解下一篇tsParticles数字营销提升品牌曝光的创新手段创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
