recover必须在defer函数中调用且仅对当前goroutine生效;漏掉任一goroutine的recover会导致panic静默终止协程并泄漏资源,如未关闭文件、连接或锁。

recover 不能在普通函数里调用,必须放在 defer 函数中,且只对当前 goroutine 生效;漏掉任一 goroutine 的 recover,panic 就会静默终止协程并可能泄漏资源。
recover 必须写在 defer 里,且只能捕获本 goroutine 的 panic
很多人在 main 函数开头加 defer func() { recover() }(),以为能兜住所有 panic —— 实际上它只对 main 自身 goroutine 有效。HTTP handler、定时任务、go func() { ... }() 启动的子协程,都得各自配 defer + recover。
常见错误现象:
- 服务日志里完全没报错,但连接数缓慢上涨、CPU 占用升高 → 很可能是某个 goroutine panic 后退出,但文件/连接/锁没清理
- 用
hystrix.Do调第三方接口,结果 panic 直接冒泡导致进程退出 → 应改用hystrix.DoC,它内部做了recover
recover 捕获到的值类型不确定,不能直接断言 error
recover() 返回 interface{},实际类型取决于 panic() 传入的参数:可能是 string、*runtime.Error、自定义 struct,甚至 int。用 err.(error) 强制断言,遇到非 error 类型会再次 panic。
立即学习“go语言免费学习笔记(深入)”;
安全做法是:
文件删除恢复功能 v0.8.0:删除前自动备份文件(存至 `delete_backup/YYYYMMDDHHMM/` 目录),支持从备份中恢复、通过清单(manifest)搜索。具备 SHA256 完整性校验、路径遍历防护及工作区根目录(workspace-root)访问限制。支持自动清理 7 天 / 30 天前的备份。 **v0.8.0:新增 `workspace_cleaner` —— 支持定时清理临时文件,并在删除前自动执行备份。** **v0.7.0:`allowed_roots` 默认值
- 用
fmt.Sprintf("%v", r)获取可读字符串,用于日志记录 - 若需结构化处理,先做类型判断:
if s, ok := r.(string); ok { ... }或if err, ok := r.(error); ok { ... } - 避免在
recover分支里继续使用已 panic 的对象(比如空指针引发的 panic,恢复后解引用仍 crash)
goroutine panic 后不处理,会导致资源泄漏而非崩溃
Go 不会回收 panic 的 goroutine,但它会释放栈内存;真正危险的是其中持有的资源:未关闭的 *os.File、未释放的 sync.Mutex、半开的 net.Conn。长期运行的服务中,反复 spawn panic 的 goroutine 会逐步耗尽句柄或连接池。
正确姿势:
- 每个可能 panic 的 goroutine 入口处,第一行就写
defer func() { if r := recover(); r != nil { /* 清理资源 */ } }() - 在
recover分支里显式调用file.Close()、conn.Close()、mu.Unlock() - 不要用
os.Exit()终止,应走srv.Shutdown()优雅下线(配合sync.Once防重复触发)
recover 不是熔断,更不是错误处理替代方案
recover 只做一件事:阻止当前 goroutine 崩溃。它不记录失败次数、不切换状态、不拒绝后续请求。把 recover 当熔断用,等于给失血病人贴创可贴。
真要构建防崩溃机制,必须组合:
- 入口处先调
breaker.Allow()判断是否允许执行 - panic 被
recover捕获后,立刻调breaker.MarkFailed() - 降级逻辑必须零依赖(不能再去查 Redis 或调下游)
- Shutdown 超时设为 10–30 秒,太短丢请求,太长拖慢滚动更新
最易被忽略的一点:recover 捕获 panic 后,业务逻辑已处于不可信状态,此时任何“重试”“回滚”“继续执行”都是危险操作 —— 它不是事务回滚机制,副作用(如 channel 发送、map 修改、DB 写入)不会自动撤销。

















