Prhub

#20625 [Bug Fix] Fix non-streaming request abort failure when --enable-metrics is enabled

sgl-project/sglang · 作者 fanghao566 · 合并时间 2026-03-23 10:58

分析状态 已生成
文件变更 3提交数 9 · 评论 13
代码增减 +151 / -0
bugfix

执行摘要

修复启用指标时非流式请求中止失效的 bug,通过修补中间件保持 ASGI receive 传递。

根据Issue #20623,当启用指标收集时,非流式请求在客户端断开(如Ctrl+C取消curl)后不会中止,因为@app.middleware("http")使用的BaseHTTPMiddleware替换了ASGI receive callable,导致request.is_disconnected()失效,影响了系统资源管理和用户体验,需要修复以恢复中止功能。

推荐精读此PR,特别是_PureASGIDispatch的设计,以了解如何处理ASGI中间件的receive传递问题,并关注测试策略从集成到单元的演变,体现了优化测试效率的实践。

讨论亮点

Review中,gemini-code-assist[bot]建议将import移动到文件顶部以遵循PEP 8风格规范;hnyls2002建议将集成测试改为使用unittest.mock的单元测试,直接测试ASGI receive传递,提高测试效率。最终,测试被重写以采纳hnyls2002的建议,从使用真实服务器(~180秒)改为轻量级单元测试,减少了执行时间。

实现拆解

实现分为三个关键部分:1) 在python/sglang/srt/utils/common.py中,添加patch_app_http_middleware(app)调用,在指标中间件应用前修补中间件;2) 新增python/sglang/srt/utils/http_middleware_patch.py,定义_PureASGIDispatch类和patch_app_http_middleware函数,提供纯ASGI中间件以传递receive不变;3) 新增test/registered/scheduler/test_abort_with_metrics.py,包含单元测试验证request.is_disconnected()的正确性和指标功能。

文件 模块 状态 重要度
python/sglang/srt/utils/http_middleware_patch.py srt/utils added 8.0
python/sglang/srt/utils/common.py srt/utils modified 7.0
test/registered/scheduler/test_abort_with_metrics.py test/scheduler added 6.0

分析完成后,这里会展示 LLM 生成的相对完整源码片段和详细注释。

关键符号

patch_app_http_middleware _PureASGIDispatch.__call__ track_http_status_code

评论区精华

代码风格改进建议 style

gemini-code-assist[bot] 建议在 http_middleware_patch.py 中将 import 移动到文件顶部以遵循 PEP 8。

结论:建议被考虑,但提交历史未显示直接修改,可能已采纳或忽略,不影响功能。 · 已解决

测试策略优化讨论 测试

hnyls2002 建议将集成测试改为单元测试,使用 mock 直接验证 ASGI receive 传递,以提高测试效率和精确度。

结论:测试被重写以采纳建议,从使用真实服务器改为轻量级单元测试,减少了执行时间。 · 已解决

风险与影响

主要风险包括:1) 中间件替换可能影响其他依赖于BaseHTTPMiddleware的中间件行为,尽管修复是局部于指标中间件;2) 修复依赖于Starlette的内部机制,如果Starlette更新可能失效;3) 测试覆盖主要针对中间件层,需要确保端到端场景也被现有测试覆盖,避免回归。

对用户:修复了bug,确保请求在客户端断开时能正确中止,避免资源浪费和潜在内存泄漏;对系统:恢复中止功能,改善内存管理和响应性;对团队:引入了一个针对Starlette已知问题的补丁,增加了维护负担,但提供了可复用的解决方案。

中间件替换风险 依赖外部库行为 测试覆盖广度

关联 Issue

#20623 [Bug] Non-streaming requests are not aborted on client disconnect when --enable-metrics is set

完整报告

执行摘要

本PR修复了启用指标时非流式请求中止失效的bug,通过引入纯ASGI中间件适配器替代Starlette的BaseHTTPMiddleware,恢复request.is_disconnected()功能,确保客户端断开时请求能正确中止。新增单元测试验证修复,不影响现有指标收集。

功能与动机

当启用--enable-metrics时,非流式请求在客户端断开(如curl被Ctrl+C取消)后不会中止,导致服务器资源浪费。Issue #20623详细描述了此问题:根因是@app.middleware("http")使用的BaseHTTPMiddleware替换了ASGI receive callable,破坏了request.is_disconnected()。修复后能恢复中止功能,提升系统资源管理。

实现拆解

  • 修补中间件:在python/sglang/srt/utils/common.py中添加patch_app_http_middleware(app)调用,在指标中间件应用前修补。
  • 纯ASGI适配器:新增python/sglang/srt/utils/http_middleware_patch.py,定义_PureASGIDispatch类,其__call__方法传递receive不变,保持request.is_disconnected()工作。
    python async def __call__(self, scope, receive, send): if scope["type"] != "http": await self.app(scope, receive, send) return request = Request(scope, receive) ...
  • 单元测试:新增test/registered/scheduler/test_abort_with_metrics.py,使用mock模拟ASGI环境,直接测试is_disconnected()行为。

评论区精华

  • gemini-code-assist[bot]:建议将import移动到文件顶部,遵循PEP 8风格规范。

    "To adhere to PEP 8 guidelines and improve code clarity, this import should be moved to the top of the file with other imports."

  • hnyls2002:建议改进测试策略,从集成测试改为单元测试,提高效率。

    "The test in test_abort_with_metrics.py launches a full server with model loading (est ~180s)... This can be tested much faster and more precisely with unittest.mock."
    最终测试被重写采纳此建议。

风险与影响

  • 技术风险:中间件替换可能干扰其他中间件;依赖Starlette内部机制,未来更新可能失效;测试覆盖主要针对中间件层,需确保端到端场景被现有测试覆盖。
  • 影响分析:用户端bug修复,避免资源浪费;系统恢复中止功能,改善内存管理;团队引入补丁增加维护负担,但提供了针对Starlette已知问题的解决方案。

关联脉络

本PR直接关联Issue #20623,是该issue的具体实现修复。未提供历史PR信息,但从讨论看,测试策略优化体现了团队对测试效率的重视,可能影响后续测试设计。

参与讨论