recover必须在actor主循环的defer中包裹整个for-select,否则panic发生时无法捕获;常见错误是将recover置于函数开头或局部逻辑,导致select内panic遗漏。

Actor模型中panic会导致整个goroutine崩溃,必须用recover兜底
Go没有内置Actor模型,但用goroutine + channel模拟时,每个Actor通常是一个独立goroutine。一旦Actor内部逻辑panic,goroutine直接退出,消息丢失、状态不一致、甚至引发级联失败。recover是唯一能拦截panic并让Actor继续处理后续消息的手段——但它**不能在任意位置调用,必须在panic发生前已处于defer链中**。
recover必须放在Actor主循环的defer里,且要包裹整个for-select
常见错误是把recover写在函数开头或局部逻辑里,结果panic发生在select分支内,defer根本没机会执行。正确做法是把整个Actor的主循环(包括for和select)包进一个匿名函数,并在其外层用defer调用recover。
使用 4 个 agent 部署一套备份与灾难恢复系统。在以下情况下使用该技能: 1. 用户希望搭建自动化的备份基础设施; 2. 用户正在配置……
func startActor(mailbox
-
recover()必须和panic()在同一个goroutine中才有效 - 不能只对
handleMessage加defer——万一panic发生在select语句本身(比如channel已关闭且无default分支),就捕获不到 - 恢复后Actor会继续下一轮
for循环,保持存活,但需注意:panic前未完成的状态变更已丢失,需靠消息幂等或外部补偿
recover后不要试图“恢复状态”,而要确保Actor可安全重入
Actor内部常维护私有状态(如map、计数器、连接句柄)。panic发生时,这些状态可能处于中间态。此时recover只是阻止崩溃,**不代表状态一致**。强行“修复”往往引入竞态或隐藏bug。
- 避免在recover块里修改共享状态或重用已损坏的资源(如已close的channel、nil指针)
- 更稳妥的做法是:记录panic上下文后,让Actor原地重启(例如退出当前goroutine,由上层spawn新Actor)
- 如果必须复用goroutine,应在recover后重置关键字段:
state = initialState(),而不是尝试回滚 - 日志中务必打印
debug.Stack(),否则线上无法定位panic源头
别在Actor外部用recover捕获,也别依赖全局panic handler
有人试图在启动Actor的父goroutine里用recover捕获子goroutine panic,这完全无效——Go中goroutine间panic不传播。也有项目加了http.DefaultServeMux那种全局panic handler,但这对Actor模型毫无意义,因为Actor的mailbox channel不会因此被清理,积压消息照旧。
- 每个Actor goroutine必须有自己的
defer recover,这是硬性要求 - 不要为省代码把recover逻辑抽成公共函数再传进Actor——它必须是该goroutine栈顶的defer项
- 测试时主动触发panic(如
panic("test"))验证recover是否生效,光看编译不报错没用
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










