Vivid

监督策略

主动上报故障、监督决策、OneForOne/OneForAll、重启钩子与僵尸状态

当子 Actor 发生 panic 或主动调用 ctx.Failed(fault) 时,父级的监督策略会根据当前故障信息决定对该子 Actor(或所有子 Actor)采取何种动作:重启、停止、恢复或升级。本文说明主动上报故障(Failed)、决策类型、OneForOne / OneForAll 策略、SupervisionContext、重启阶段钩子与重启失败与僵尸状态。在创建 Actor 时通过 Actor 配置WithActorSupervisionStrategy 或系统级的 WithActorSystemSupervisionStrategy 注入。

主动上报故障(Failed)

当 Actor 在处理消息时遇到无法在内部恢复的异常(如依赖不可用、数据严重错误),可调用 ctx.Failed(fault) 主动上报。fault 为任意 Message,用于向父级描述原因。父级会根据其监督策略做出决策(重启、停止、恢复或升级)。调用后当前处理流程可能被中断,建议仅在确实无法自行恢复时使用。

监督流程:故障 → 决策 → 动作
加载图表…

监督决策类型

决策由(SupervisionDecision) SupervisionStrategyDecisionMakerMakeDecision(ctx) 返回,可选常量如下:

决策含义
SupervisionDecisionRestart重启子 Actor(立即,不处理剩余队列)
SupervisionDecisionGracefulRestart优雅重启(处理完当前与队列后再重启)
SupervisionDecisionStop停止子 Actor(立即)
SupervisionDecisionGracefulStop优雅停止(处理完再停止)
SupervisionDecisionResume恢复,不重启不停止,子 Actor 继续运行
SupervisionDecisionEscalate升级,由父级的父级(或系统顶层)处理;顶层默认行为为停止

可通过 decision.IsRestart()IsStop()IsResume()IsEscalate()IsGraceful() 等辅助方法判断决策类型。

SupervisionContext

决策器的 MakeDecision(ctx SupervisionContext) 会收到当前监督上下文,用于根据故障与子级信息做出决策:

方法说明
Logger()当前日志,便于记录决策原因
Child()仅包含触发本次监督的子 ActorRef(单个)
Children()当前父级下的所有子 ActorRefs
Fault()导致触发的故障消息(panic 时可为 nil 或包装信息)
FaultStack()故障时的堆栈([]byte)

OneForOne 仅对 Child() 应用决策;OneForAll 对 Children() 全部应用同一决策。

OneForOne 与 OneForAll

  • OneForOneStrategy(decisionMaker, options...):仅对触发监督的那一个子 Actor 应用决策。适用于子 Actor 彼此独立、故障隔离的场景。
  • OneForAllStrategy(decisionMaker, options...):对当前上下文下所有子 Actor 应用同一决策。适用于需要整体重置或协调的场景。

两者均接受 SupervisionStrategyDecisionMakerFN 或实现 SupervisionStrategyDecisionMaker 的决策器,以及可选的退避选项(InitialDelay、MaxDelay、Factor、Jitter),用于在重启/停止前加入延迟与抖动,避免 thundering herd。

决策器示例

根据故障类型或子级信息决定恢复或重启:

maker := vivid.SupervisionStrategyDecisionMakerFN(func(ctx vivid.SupervisionContext) (vivid.SupervisionDecision, string) {
    if ctx.Fault() == nil {
        return vivid.SupervisionDecisionResume, "no fault"
    }
    // 可根据 Fault()、ctx.Child()、ctx.Children()、FaultStack() 等细化逻辑
    return vivid.SupervisionDecisionRestart, "restart on fault"
})
strategy := vivid.OneForOneStrategy(maker)

ref, _ := ctx.ActorOf(&MyActor{}, vivid.WithActorSupervisionStrategy(strategy))

系统顶层若不设置 WithActorSystemSupervisionStrategy,默认行为为停止(Stop),并记录“已达默认顶层监督策略”的说明。

与 Actor 提供者(Provider)配合

当决策为重启时,若该 Actor 创建时配置了 WithActorProvider(provider),系统会通过 provider.Provide() 获取新实例替换原 Actor;未配置则重启不替换实例。详见 Actor 配置 - Actor 提供者

重启阶段的扩展钩子(PreRestart / Restarted)

当监督决策为重启时,被重启的 Actor 可在以下两个阶段挂载可选逻辑:

接口方法调用时机
PreRestartActorOnPreRestart(ctx RestartContext) error监督触发重启;返回 error 则中止本次重启
RestartedActorOnRestarted(ctx RestartContext) error重启完成后;返回 error 仅记录,不阻止运行

RestartContext 提供 Logger()Ref(),可在钩子内打日志或获取当前 Actor 引用;不提供消息发送、子 Actor 创建等运行时能力。与首次启动相关的 PrelaunchActor创建与生命周期 - 启动阶段:PrelaunchActor

便捷构造器

在不定义新类型的前提下挂载重启钩子,可使用:

  • vivid.NewPreRestartActor(preRestartFn, actor)
  • vivid.NewRestartedActor(restartedFn, actor)

未传入的 actor 会使用占位空实现。若 OnRestarted / OnPreRestart 等钩子失败,该 Actor 会进入 僵尸状态,需通过 Kill 或随系统/父级退出才能释放。

重启失败与僵尸状态

当子 Actor 在监督触发重启的过程中失败(如 OnRestartedOnPreRestartOnPrelaunch 返回错误,或重启流程内部异常)时,系统不会无限重试,也不会向父级上报,而是将该 Actor 标记为僵尸状态

  • 含义:该 Actor 仍占用其 ActorRef 与邮箱,但不再执行任何业务逻辑。后续消息由框架以“空行为”处理(仅投递与邮箱排空,不调用用户 OnReceive),避免错误逻辑继续执行或状态扩散。
  • 影响
    • 发往该 ref 的 Tell/Ask 仍可投递,但无业务处理;Ask 可能超时或得不到预期回复。
    • 该 ref 仍存在,若被缓存或对外暴露,调用方可能继续向“已失效”的 Actor 发消息,需在业务层通过监控或超时发现。
    • 父级不会收到该子 Actor 的 OnKilled(因未从系统移除),若父级依赖“子死亡”做清理或重建,需通过日志、监控或健康检查发现僵尸并主动 Kill
  • 解除:僵尸状态不会自动恢复。只有以下情况该 Actor 才会被释放、引用失效:
    • 显式终止:对 ref 调用 Kill(ref, ...),僵尸会走正常终止流程并从系统移除。
    • 随系统或父级退出ActorSystem.Stop() 或父 Actor 被终止时,整棵子树(含僵尸子 Actor)会被一并清理。

建议保证 OnRestarted / OnPreRestart 等钩子尽量可成功,或通过“重启失败;actor is now in zombie state”日志做监控与告警,必要时对对应 ref 执行 Kill。发起终止见 创建与生命周期 - 发起终止

On this page