context.Err() 返回错误是状态反馈而非异常,cancel() 关闭 Done 通道后 Err() 幂等返回 context.Canceled 等终态错误,需及时检查而非忽略或延迟响应。
调用 cancel
函数后,context.Err() 返回错误,不是因为“出错了”,而是明确告诉你:这个 context 已被主动取消或超时结束。它本质是状态反馈,不是异常信号。
cancel() 的核心动作是关闭 ctx.Done() 返回的 channel。Go 规定:一旦 channel 关闭,ctx.Err() 就不再返回 nil,而是立即返回具体错误值:
context.Canceled
context.DeadlineExceeded
ctx.Err() 每次调用都返回相同结果,不会改变 context 状态,也不阻塞。它只是检查内部 err 字段是否已被设置:
很多问题其实源于没在关键路径上及时响应 Err():
单纯看 ctx.Err() 只知道“被谁取消”,但不知道“谁发起的取消”。要定位根因:
Err() == errors.New("order timeout: payment service unresponsive")
ctx.Err().Error() + 当前函数名,比只打 "context canceled" 有用得多基本上就这些。Err 不是 bug,是 context 设计里最诚实的状态出口。