Vivid

错误处理

vivid 错误体系、错误码与错误链、errors.Is/As 判定与预定义错误码一览

Vivid 使用 *vivid.Error 表示框架内可序列化、带错误码与错误链的异常。可与 Go 标准库 errors.Is、errors.As 配合做精确判定或统一兜底。本文说明错误类型的设计、判定方式、错误链与 cause 的含义,以及预定义错误码分类。监督与故障上报见 监督策略、创建与生命周期 - Failed。

概述

特性说明
错误码(code)每个错误对应唯一 int32,用于日志、监控与跨进程/节点一致识别;可序列化传播。
可读描述(message)人类可读说明,出现在 Error() 字符串中;序列化时一并传输。
错误链支持通过 With(err) 包装底层错误,实现 Unwrap,便于 errors.Is / errors.As 递归匹配。
与标准库一致实现 error 接口及 Is / As / Unwrap,与 errors 包行为一致。

因此你可以:按错误码做细粒度处理或监控;用 errors.Is(err, vivid.ErrorXxx) 做语义判定;用 errors.Is(err, vivid.ErrorNotFound) 等做统一兜底。

核心类型:*vivid.Error

*vivid.Error 是框架内错误的统一表示,可在分布式环境中序列化传播(仅 code 与 msg 参与序列化;包装的底层错误不参与,反序列化时通过 QueryError(code) 还原为注册的 *Error 实例)。

常用方法与行为

方法 / 行为说明
GetCode() int32返回错误码,用于日志、监控或跨节点一致判定。
GetMessage() string返回可读描述(不含 [vivid: code] 前缀)。
Error() string实现 error 接口,格式为 [vivid: <code>] <msg>。
With(err error) *Error包装底层错误 err,生成新 *Error;Unwrap() 返回 err,errors.Is / errors.As 会沿链递归。
WithMessage(msg string) *Error在原有描述后追加说明,不改变错误码;Unwrap() 返回接收者自身。

判定方式:errors.Is 与 errors.As

使用标准库 errors.Is 判断“是否等同于某预定义错误”;使用 errors.As 将错误断言为 *vivid.Error 后读取 code 或 message:

if errors.Is(err, vivid.ErrorActorAlreadyExists) {
    // 同父下名称重复
}
if errors.Is(err, vivid.ErrorFutureTimeout) {
    // Ask 超时
}
var vividErr *vivid.Error
if errors.As(err, &vividErr) {
    code := vividErr.GetCode()
    msg := vividErr.GetMessage()
}

错误链与 cause(统一兜底)

部分预定义错误在注册时就挂载了底层 cause,形成一条短链。这样做的目的是:保持该错误的 code 与 message 不变,同时让 errors.Is 能同时命中具体错误和父类错误,便于统一兜底。

例如:ErrorRefNilAgent(AgentRef 为 nil)在语义上属于“资源不存在”,因此注册时挂载 ErrorNotFound 为 cause。返回给调用方的仍是 code=130005、message=agent ref is nil,但 errors.Is(err, vivid.ErrorRefNilAgent) 与 errors.Is(err, vivid.ErrorNotFound) 均为 true。

概念关系如下:

ErrorRefNilAgent 的错误链:同一 err 可同时命中具体错误与父类
加载图表…

两类父类错误

父类含义会同时命中该父类的具体错误(示例)
ErrorNotFound资源不存在ErrorRefEmpty、ErrorRefNilAgent
ErrorIllegalArgument参数无效或格式不合法ErrorRefFormat、ErrorRefInvalidAddress、ErrorRefInvalidPath、ErrorFutureInvalid、ErrorInvalidMessageLength、ErrorCronParse

因此可以按需编写:细粒度逻辑(如针对 ErrorRefNilAgent 单独提示)或粗粒度兜底(如对所有 ErrorNotFound 统一返回 404、对所有 ErrorIllegalArgument 统一返回 400)。

判定流程示意

errors.Is(err, target) 会沿 Unwrap 链递归:先看当前节点是否与 target 匹配(对 *Error 比较 code),若不匹配且存在 Unwrap(),则对底层错误继续 Is。因此“带 cause 的预定义错误”会同时匹配自身与 cause。

errors.Is 沿错误链递归匹配
加载图表…

预定义错误码一览

预定义错误按功能领域分组,错误码按区间划分,与代码中 RegisterError 一致,便于查找与扩展。完整列表与错误码见 pkg.go.dev - vivid。

系统与运行时

ActorSystem 生命周期、重复启停及通用“资源不存在”。

代码变量名说明父类
-1ErrorException未分类内部异常—
100000ErrorNotFound资源不存在(如调度器 Cancel 时指定 reference 不存在)—
100001ErrorActorSystemAlreadyStarted重复调用 Start—
100002ErrorActorSystemAlreadyStopped重复调用 Stop—
100003ErrorActorSystemStartFailed系统启动失败—
100004ErrorActorSystemStopFailed系统停止失败—
100005ErrorActorSystemNotStarted未启动时调用 Stop—
100006ErrorActorSystemStopped系统已停止—

Actor 与生命周期

Actor 创建、预启动及存活状态。

代码变量名说明父类
100100ErrorActorDeadedActor 已死亡(如在已死亡父级上创建)—
100101ErrorActorAlreadyExists同父下名称重复—
100102ErrorActorSpawnFailedActor 创建失败—
100103ErrorActorPrelaunchFailed预启动(Prelaunch)失败—

Future 与消息

Ask/Result、Future 生命周期及消息长度与缓冲读取。

代码变量名说明父类
110000ErrorFutureTimeoutResult/Wait 超时未收到应答—
110001ErrorFutureMessageTypeMismatch应答类型与泛型声明不一致—
110002ErrorFutureUnexpectedError收到非预期错误—
110003ErrorFutureInvalid创建 Future 时参数非法(如 timeout)ErrorIllegalArgument
110004ErrorInvalidMessageLength消息长度非法(如 Remoting 协议层)ErrorIllegalArgument
110005ErrorReadMessageBufferFailed读消息缓冲失败—

参数与调度

调用参数不合法及调度器(如 Cron)解析失败。

代码变量名说明父类
120000ErrorIllegalArgument参数无效或缺失—
120001ErrorCronParseCron 表达式解析失败ErrorIllegalArgument

ActorRef

ActorRef 解析、格式及 Agent 引用。

代码变量名说明父类
130001ErrorRefEmptyActorRef 为空ErrorNotFound
130002ErrorRefFormatActorRef 格式错误(须包含 address 与 path)ErrorIllegalArgument
130003ErrorRefInvalidAddress地址非法ErrorIllegalArgument
130004ErrorRefInvalidPath路径非法ErrorIllegalArgument
130005ErrorRefNilAgentAgentRef 为 nilErrorNotFound

远程通信

跨节点消息发送、编解码、握手与处理。

代码变量名说明父类
140000ErrorRemotingMessageSendFailed远程消息发送失败—
140001ErrorRemotingMessageEncodeFailed远程消息编码失败—
140002ErrorRemotingMessageDecodeFailed远程消息解码失败—
140003ErrorRemotingMessageHandleFailed远程消息处理失败—
140004ErrorRemotingHandshakeFailed远程握手失败—

集群

集群名称校验、加入控制及未启用时的调用。详细说明见 集群错误。

代码变量名说明父类
150000ErrorClusterNameMismatch集群名称不匹配—
150001ErrorClusterDisabled集群已禁用(未启用集群时调用 ClusterContext 方法会返回此错误)—
150002ErrorClusterNodeStatusMismatch节点状态不匹配—
150003ErrorClusterNotInQuorum当前不在多数派—
150004ErrorClusterJoinAuthFailedJoin 认证失败—
150005ErrorClusterJoinRateLimitedJoin 请求被限流—
150006ErrorClusterProtocolVersionMismatch集群协议版本不兼容—
150007ErrorClusterJoinNotAllowed地址或 DC 不在白名单—
150008ErrorClusterAdminAuthFailed管理操作 Token 无效—

RegisterError 用于在包 init 或启动阶段注册自定义错误码,供跨节点一致识别;可选 optionalCauses 在注册时挂载父类错误,不改变 code 与 message,仅便于 errors.Is / errors.As 命中。

On this page