客户端断开后日志里仍能看到那批查询继续跑完,ctx 明明是从外面一路传进来的,`ctx.Done()` 一次都没触发,接口照样占着连接直到超时,下游压力迟迟降不下来。日志里能对上时间点,这种反而好排。
中间某层图省事用了 `context.Background()` 或 `context.TODO()` 重新造上下文,父子链被切断,外层的 cancel 传不进来,下游所有 select 都等不到 Done 信号,只能等自己的超时,问题藏在很深的调用层里。这一点先确认清楚,后面就不用反复试。
grep -rn 'context.Background()' --include='*.go' . grep -rn 'context.TODO()' --include='*.go' . go vet ./...
「context cancel 失效」排查到最后往往是很小的一处差异,前面那些复杂猜测可以先放一放。能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。
处理上按这个顺序:全局搜出背景上下文和 TODO 的调用点,逐个确认用途;把每一层的入参都改成透传上游上下文不要新建;在出口处打印取消原因确认信号真的传到这里。
结果对不对很好判断,客户端断开后一秒内日志出现取消记录,查询立即停下不再跑完。
