Vivid

错误处理

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

Vivid 使用 *vivid.Error 表示框架内可序列化、带错误码与错误链的异常。可与 Go 标准库 errors.Iserrors.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 是框架内错误的统一表示,可在分布式环境中序列化传播(仅 codemsg 参与序列化;包装的底层错误不参与,反序列化时通过 QueryError(code) 还原为注册的 *Error 实例)。

常用方法与行为

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

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

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

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=130005message=agent ref is nil,但 errors.Is(err, vivid.ErrorRefNilAgent)errors.Is(err, vivid.ErrorNotFound) 均为 true

概念关系如下:

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

两类父类错误

父类含义会同时命中该父类的具体错误(示例)
ErrorNotFound资源不存在ErrorRefEmptyErrorRefNilAgent
ErrorIllegalArgument参数无效或格式不合法ErrorRefFormatErrorRefInvalidAddressErrorRefInvalidPathErrorFutureInvalidErrorInvalidMessageLengthErrorCronParse

因此可以按需编写:细粒度逻辑(如针对 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