熔断库如hystrix-go/gobreaker不支持context自动透传,因其Do/Execute接口无context.Context参数,需手动在闭包中显式传递并用于下游调用,否则将导致超时取消失效、goroutine泄漏及连接数暴增。

Context 不能靠熔断库自动透传,必须手动塞进业务函数里 —— 否则超时、取消信号全丢,goroutine 泄漏风险极高。
为什么 hystrix-go / gobreaker 的 Do/Execute 不处理 context
这两个库的 Do 和 Execute 接口签名里根本没有 context.Context 参数,它们只管“执行函数 + 捕获 error”,对请求生命周期完全无感。你传进去的闭包里如果没显式用 ctx,那整个链路就等于裸奔。
- 常见错误:在
Do闭包里直接调http.Get(url),没带 context → 超时后 TCP 连接还挂着,goroutine 卡死 - 更隐蔽的问题:闭包里调了 gRPC 客户端,但没传
ctx→ctx.Done()信号根本到不了底层 transport 层 - 后果不是“降级失败”,而是“服务越压越慢,CPU 上不去但连接数爆表”
正确做法:把 context 作为参数显式传进闭包
别指望熔断器帮你管理上下文,它只做开关;你得自己把 ctx 带进业务逻辑里,再由业务逻辑向下透传。
- 用
hystrix.Do时,闭包要接收ctx并用于下游调用:func() error { return callWithCtx(ctx) } - 用
gobreaker.Execute时同理:cb.Execute(func() (interface{}, error) { return callWithCtx(ctx) }) - 如果你封装了统一调用函数(比如
callUserSvc(ctx, id)),就直接把它塞进闭包,别在闭包里再造新 context - 绝对不要在闭包里写
context.Background()或context.TODO()—— 这等于主动切断链路
网关层最容易漏传 context 的三个位置
网关是 context 透传最脆弱的一环,漏一处,整条链路就断。
立即学习“go语言免费学习笔记(深入)”;
- 路由匹配后、调用前没执行
req = req.WithContext(ctx)→ 下游 HTTP handler 收不到 cancel - 调用 gRPC 时用了
client.GetUser(context.Background(), ...),而不是client.GetUser(req.Context(), ...) - 降级函数里又发起新请求(比如查缓存),但新请求没带原
ctx→ fallback 自身变成黑洞
自定义熔断器必须支持 context 的两个硬要求
如果你自己写 CircuitBreaker,不支持 context 就等于没写完。
-
Execute方法签名必须含ctx context.Context参数,且保证它被传进业务函数 - 状态切换和滑动窗口统计本身不能阻塞
ctx.Done(),比如轮询健康检查不能用time.Sleep,得用time.AfterFunc或 select 配合ctx.Done()
真正难的不是加个参数,而是确保从入口 http.Request 开始,每一层调用都显式透传、不丢失、不覆盖 —— 这种链路完整性,没法靠库自动补全。


















