errgroup.group 是 go 中异步流水线错误传播的首选工具,基于 context.context 实现协作取消,需各阶段显式检查 ctx.err() 以确保短路,否则存在资源泄漏风险。

Go 中 errgroup.Group 是异步流水线错误传播的首选工具
直接用 errgroup.Group 替代手写 sync.WaitGroup + 全局错误变量,能天然支持“任一 goroutine 出错即取消其余任务”——这是异步流水线异常管理的核心诉求。
它不是语法糖,而是基于 context.Context 实现的协作取消机制。只要所有子任务都接收并响应同一个 ctx,就能在首个错误发生时自动中断后续执行。
-
errgroup.Group的Go方法会自动绑定当前ctx,无需手动传参;但你仍需在子函数内部检查ctx.Err()并提前返回 - 若子任务未主动监听
ctx.Done(),即使主 goroutine 已因错误退出,该子任务仍可能继续运行(资源泄漏风险) -
errgroup.WithContext返回的ctx是带取消能力的衍生上下文,不要用context.Background()或context.TODO()替代
流水线各阶段必须显式检查 ctx.Err() 才能真正实现短路
很多开发者以为用了 errgroup.Group 就万事大吉,结果发现错误发生后其他阶段还在跑——根本原因是没在每个阶段里做上下文检查。
尤其注意 I/O 操作(如 HTTP 请求、数据库查询、文件读写),它们通常自带 ctx 参数,但自定义逻辑(比如数据转换、校验、序列化)容易被忽略。
- 在循环或递归处理中,每次迭代开头加
if ctx.Err() != nil { return ctx.Err() } - 调用第三方库方法时,优先选接受
context.Context的版本(如http.NewRequestWithContext而非http.NewRequest) - 阻塞型操作(如
time.Sleep)应改用select+ctx.Done()实现可取消等待
errgroup.Group 的错误返回行为:只返回第一个非 nil 错误
这既是优点也是陷阱。优点是避免错误堆积干扰判断;陷阱是——如果第一个错误是网络超时,而第二个是数据校验失败,你将永远看不到后者。
实际开发中,往往需要区分“终止性错误”(如上下文取消、连接中断)和“业务错误”(如参数非法、状态冲突)。前者应立即传播,后者有时需收集汇总。
- 默认行为下,
Group.Wait()返回的是首个非nil错误,不会合并多个错误 - 若需聚合错误,得自己维护一个
sync.Mutex+[]error,并在每个子任务结尾追加(注意并发安全) - 对日志调试而言,建议在每个子任务出错时立刻打点:
log.Printf("stage X failed: %v", err),别等最后统一处理
不要在子任务里 recover panic,除非你明确知道要做什么
流水线中某个阶段 panic 会导致整个 goroutine 崩溃,errgroup.Group 默认不捕获 panic,它只会收到 context.Canceled 或 context.DeadlineExceeded 这类正常错误。
盲目加 defer/recover 容易掩盖真实问题,还可能让错误静默丢失。
- 如果某阶段确实可能 panic(比如解析不可信 JSON),应在该阶段内
recover并转为返回fmt.Errorf("parse failed: %w", err) - 切勿在顶层 goroutine 里统一
recover——这会让错误来源模糊,且无法与上下文取消逻辑对齐 - panic 应该是程序异常,不是控制流手段;用 error 返回才是 Go 的惯用做法
ctx.Err() 检查,整条流水线就可能卡在不该卡的地方。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











