子goroutine必须用context.WithCancel(parent)而非context.Background(),因为Background()创建不可取消的根上下文,会切断取消传播链,导致上游cancel后下游完全无感;WithValue仅包装不改变取消能力,若源ctx不可取消则包装后仍不可取消;select中仅收Done消息就return会忽略后续可能的清理逻辑,应确保资源释放后再退出。

Context取消机制不是“加个参数就完事”,它必须嵌入调用链每一层,否则下游协程根本收不到上游 cancel 信号。
为什么子 goroutine 必须用 context.WithCancel(parent) 而不能用 context.Background()
直接用 context.Background() 或 context.TODO() 启动子 goroutine,等于主动切断取消传播链——上游一 cancel,下游完全无感,协程和资源全卡死。
- HTTP handler 收到的
req.Context()是可取消的;但若你在里面写go doWork(context.Background()),这个 goroutine 就彻底脱离管控 -
context.WithValue(ctx, key, val)只是包装,不改变取消能力:如果传入的ctx本身不可取消(比如Background()),那包装后依然不可取消 - 调试时可用
fmt.Printf("parent.Err(): %v, child.Err(): %v", parent.Err(), child.Err())验证父子 Err 是否同步变化
select 监听 ctx.Done() 时,为什么不能只收消息就 return
case 触发只说明通道关闭了,但关闭原因不同,业务响应也该不同。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
-
errors.Is(ctx.Err(), context.Canceled)表示被显式 cancel(如客户端断连),通常应立即释放资源、不重试 -
errors.Is(ctx.Err(), context.DeadlineExceeded)表示超时,可能需记录日志、触发降级或有限重试 - HTTP client 返回
context.Canceled,若误判为网络错误而重试,会放大上游已放弃的请求压力 - 关键资源(如 DB 连接、文件句柄)清理逻辑不能只靠
defer:panic 时 defer 不执行,必须在case 分支内显式关闭
errgroup.Group 里为什么每个 goroutine 还得自己监听 ctx.Done()
errgroup.WithContext(ctx) 只是给 group 设置默认 context,它不会自动把 ctx 注入到你传给 group.Go() 的函数里。
立即学习“go语言免费学习笔记(深入)”;
- 如果你的 worker 函数签名没带
ctx context.Context参数,或者接收了但没在内部 selectctx.Done(),那它对 cancel 完全免疫 - 正确写法是:
g.Go(func() error { return doWork(ctx) }),且doWork内部必须自己监听ctx.Done() - 别指望 errgroup “代劳”取消传播——它只聚合错误,不代理信号
最常被忽略的一点:Context 的取消树是单向的,父 cancel 带动子 cancel,但子 cancel 不影响父。这意味着,你不能靠子 context 的 cancel 来“通知上游”,想做反向控制就得另建 channel 或用其他机制。取消信号一旦发出,就没有“撤回”或“忽略”的余地。

















