recover只能捕获当前goroutine的panic,worker池中每个worker必须独立用defer-recover处理,否则panic会导致任务堆积、channel阻塞;recover后须立即清理资源、上报监控并触发熔断,不可继续执行。

直接在 main 函数或启动 goroutine 外层加 recover 对 Worker 池完全无效——每个 worker 必须独立捕获 panic,否则一个任务崩溃就让整个池子静默退出。
每个 worker goroutine 都要包一层 defer-recover
Worker 池里每个长期运行的 goroutine 都是独立调度单元,recover 只对当前 goroutine 生效。漏掉任何一个,panic 就会终止该 worker,导致任务队列堆积、channel 阻塞、后续任务永远得不到处理。
- 必须在每个
startWorker或worker()函数最开头写defer func() { if r := recover(); r != nil { log.Printf("worker panic: %v", r) } }() - 别把 recover 放在 for-select 外围却忘了它只覆盖一次循环——recover 要在函数入口就注册,不是在 for 内部
- 如果 worker 里还启了子 goroutine(比如发 HTTP 请求后开协程处理回调),那些子协程也得各自加 recover,不能指望外层兜住
recover 后不能继续“假装正常”,必须配合状态反馈与熔断
recover 只是止血,不是痊愈。高频 panic 往往意味着下游服务异常、数据污染或逻辑缺陷,硬扛只会让问题雪球越滚越大。
- 每次 recover 捕获 panic 后,必须调用熔断器的
MarkFailed()(如gobreaker的cb.MarkFailed()),否则失败计数不涨,熔断器永远不会跳闸 - 任务提交前必须先过
breaker.Allow(),返回 false 就立刻降级或返回 429,而不是等进到 worker 再 panic - 别依赖
hystrix-go.Do:它内部不 recover,panic 会直接冒泡;改用DoC,它才做兜底并转成可判断的*hystrix.Error
recover + Shutdown 要协同,避免资源泄漏比崩溃更危险
panic 频发时,真正的高可用动作是快速止损,而不是靠 recover 维持虚假健康。
- recover 块里禁止调
os.Exit()——k8s 或 systemd 会判定为 crash,触发反复重启 - 应使用
sync.Once控制只触发一次srv.Shutdown(),停止接收新请求,同时等待活跃连接自然结束 -
Shutdown超时建议设为 10–30 秒:太短丢请求,太长拖慢滚动更新;超时后可强制os.Exit(1),但仅限兜底 - 如果 worker 里用了数据库连接、HTTP 客户端或文件句柄,recover 后必须显式清理,否则连接/句柄持续泄漏
最容易被忽略的是:recover 不等于错误处理完成。它只是给了你一次干预机会,之后是否降级、是否上报、是否触发告警、是否关闭服务,全靠你在 recover 块里手动补全——漏掉任何一环,都可能让一次小故障演变成服务雪崩。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











