errgroup.WithContext是唯一安全初始化方式,必须传入带超时的context;GoContext()用于可取消IO操作,Go()仅适用于纯CPU计算;Wait()只返回首个错误且不捕获panic。

errgroup.WithContext 是唯一安全的初始化方式
直接 new(errgroup.Group) 或 errgroup.Group{} 会丢失上下文控制能力——超时、取消全部失效,任务失败后可能永久卡住。必须用 errgroup.WithContext 初始化,并传入带超时的 context。
- 错误写法:
var g errgroup.Group→ 后续调用g.Wait()无法响应超时,ctx.Err() 永远为 nil - 正确写法:
g, ctx := errgroup.WithContext(context.WithTimeout(context.Background(), 5*time.Second)) - 超时时间要覆盖整个任务链(比如 HTTP 请求 + JSON 解析 + 写文件),不能只包某一步
- 第三方库(如
http.Client)必须显式使用WithContext方法,否则 errgroup 的超时会被绕过
Go() 和 GoContext() 到底该选哪个
Go() 只接受无参函数,完全不感知 context;GoContext() 显式接收 ctx 参数,并在内部自动监听 ctx.Done(),适合所有可取消的 IO 操作。
- HTTP 请求、数据库查询、文件读写 → 必须用
GoContext(),否则 context 取消后 goroutine 继续跑,资源泄漏、错误被掩盖 - 纯 CPU 计算(如 base64 编码、简单数学运算)→ 可用
Go(),但得确保它真的不阻塞、不依赖外部状态 - 混用风险高:一个用
Go(),另一个用GoContext(),前者可能还在跑,后者已退出,Wait() 返回后你根本不知道它是否完成 - 示例:
g.GoContext(func(ctx context.Context) error { return http.GetWithContext(ctx, url) })
Wait() 返回 nil 不代表全成功
errgroup.Wait() 返回 nil,只表示「所有已启动的任务都完成了,且没报告非 nil 错误」——但它不检查 panic,也不保证每个 goroutine 都真正执行完毕。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 某个任务里
panic("boom"),又没recover(),整个程序崩溃,根本走不到Wait() - 多个任务返回错误,
Wait()只保留第一个(按完成顺序),其余被丢弃;如果关键错误是第二个,你就收不到 - 必须在每个
Go()或GoContext()闭包里显式return err,不能只log.Printf - 需要全量错误?别依赖
Wait(),改用sync.Mutex+[]error手动收集,或chan error配缓冲(容量至少为任务数)
重试必须闭环在单个 Go() 函数内
errgroup.Wait() 等的是所有通过 Go() 提交的 goroutine 结束——哪怕你在里面 for 循环重试三次,只要没退出函数,就一直算“运行中”。
立即学习“go语言免费学习笔记(深入)”;
- 错误模式:外层循环反复调用
g.Go()做重试 → 并发数爆炸,实际 goroutine 数远超预期 - 正确做法:每个任务自己管理重试逻辑,成功则
return nil,彻底失败则return err - 每次重试前都要检查
ctx.Err() != nil,否则可能白跑好几轮才响应超时 - 所有可能 panic 的地方(JSON 解析、第三方库调用)必须加
defer func() { recover() }(),并转成 error 返回,否则 Wait() 会 panic
ctx.Done() 或 ctx.Err() 并及时退出。**

















