Skip to content

🐯 [资源] 每请求新建 context 无上层传播 · peerpool.go #269

Description

@github-actions

来自 #268 的架构级评审建议。不阻塞合入,仅供参考是否有更好的架构解法。

⚠️ [重要 · 资源] 每请求新建 context 无上层传播 cluster/peerpool.go:91

问题根因:PeerPool.ctx() 用 context.Background() 做根、每次转发都新建一个独立的 WithTimeout 上下文。这意味着转发的超时不由调用链上游(客户端→入口节点的原始请求上下文)控制:入口节点的原请求或许早已被客户端取消/超时,但 PeerPool 仍会继续向属主节点发出完整操作直到自己的 timeout。且这种「每请求申请一个独立 context」的写法无法摊销——每个转发请求都分配一次上下文对象。

为什么低级解法不够:通用评审会建议『把 PeerPool.Put/Get 的 ctx 参数化、由调用方传入』。这确实是正确的方向,但仅仅把参数传下去还不够——需要把 service.Router.handleGet/handlePut 里的转发调用也接到当前请求的连接/上下文上,这在 bannet 的 request 模型里目前没有对应的 context 传递通道。

架构级方案:这是典型的热路径 per-call 分配与生命周期归属问题。架构级方案:(1) 让转发 API 接受调用方传入的 ctx(而非每次自建 Background 根),由 service.Router 构造 request 时从 bannet.Request 的底层连接拿一个可取消的上下文,形成「客户端取消 → 入口取消 → 转发取消」的端到端取消传播;(2) 若 bannet 无法轻易把 ctx 挂到 request 上,则至少给 PeerPool 的 ctx() 加一个可复用/常驻的超时句柄,避免每个转发请求都做一次 time 分配。原则:转发的生命期应绑定到原始请求的生命期,而不是背书一个全新的、与调用方脱钩的超时时钟。

代价/收益:代价:需要给 bannet.Request 或连接注入 ctx 传递机制(接口改动 + 各调用点调整)。收益:取消与超时不再孤立,过载/关停时转发能及时停止,消除每个转发请求多余的一次 context 分配。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions