Prhub

#28002 Fix circular import when sglang.srt.model_executor.runner_backend is imported first

原始 PR 作者 jvmncs 合并时间 2026-06-17 03:04 文件变更 4 提交数 6 评论 3 代码增减 +4 / -5

执行摘要

修复 runner_backend 循环导入导致的 CI 失败

base-b-test-cpu (Xeon) job 在 main 分支及每个 PR 上失败,错误为 AttributeError: module 'sglang.srt.model_executor' has no attribute 'runner_backend'。实际上是由于循环导入:runner_backend 模块导入 runner.shape_key 时触发 runner/__init__,进而重新进入 runner_backend 导致未初始化。该问题只在 mock.patch 的 dotted-name 解析路径下暴露。

建议所有涉及循环依赖修复的 PR 参考此模式:当符号仅用于类型注解时,利用 TYPE_CHECKINGfrom __future__ import annotations 延迟导入。此 PR 展示了清晰的诊断和最小化修复,值得精读。

讨论亮点

作者在 PR 描述中详细分析了循环导入的精确路径:runner_backend/__init__ -> base_cuda_graph_backend -> runner.shape_key (executes runner/__init__) -> decode_cuda_graph_runner -> runner_backend.breakable_cuda_graph_backend -> base_cuda_graph_backend。该分析揭示了仅当 runner_backend 作为入口时才会触发,因此某些 CI job 不失败。reviewer ch-wan 直接批准,无进一步讨论。

实现拆解

  1. 在四个 runner_backend 文件中,将全局的 from sglang.srt.model_executor.runner.shape_key import ShapeKey 删除。
  2. 在已有 TYPE_CHECKING 块内添加 from sglang.srt.model_executor.runner.shape_key import ShapeKey,因为 ShapeKey 仅在类型注解中使用。
  3. 所有四个文件已包含 from __future__ import annotations,因此类型注解在运行时不会被求值,导入移入 TYPE_CHECKING 后不会影响实际行为。
  4. 不影响测试或其他配置,无需额外改动。
文件 模块 状态 重要度
python/sglang/srt/model_executor/runner_backend/base_cuda_graph_backend.py 模型执行器 modified 5.2
python/sglang/srt/model_executor/runner_backend/breakable_cuda_graph_backend.py 模型执行器 modified 4.7
python/sglang/srt/model_executor/runner_backend/full_cuda_graph_backend.py 模型执行器 modified 4.7
python/sglang/srt/model_executor/runner_backend/tc_piecewise_cuda_graph_backend.py 模型执行器 modified 4.7

关键源码片段

python/sglang/srt/model_executor/runner_backend/base_cuda_graph_backend.py import

作为抽象基类,是所有 CUDA 图后端的共同父类,修复必须从此开始。

"""Backend interface for CUDA graph capture/replay."""
from __future__ import annotationsfrom abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Callable, Iterator, Optionalimport torch# ShapeKey 仅用于类型注解,移入 TYPE_CHECKING 避免循环导入
if TYPE_CHECKING:
    from sglang.srt.model_executor.forward_batch_info import ForwardBatch
    from sglang.srt.model_executor.runner.shape_key import ShapeKey
​
​
class BaseCudaGraphBackend(ABC):
    """Pure ABC: no state, no defaults."""
    # ... 类方法保持不变

评论区精华

循环导入根因分析 正确性

作者在 PR 描述中详细追踪了导入链:runner_backend -> runner.shape_key -> runner/__init__ -> runner_backend,并指出 mock.patch 的 dotted-name 解析方式会吞掉 ImportError 转为 AttributeError。

结论:将 ShapeKey 移入 TYPE_CHECKING 块即可打破循环,不需要修改业务逻辑。 · 已解决

风险与影响

变更极小(仅导入位置移动),且四个文件均已使用 from __future__ import annotations,运行时不会执行 TYPE_CHECKING 块内的导入。回归风险极低。但需注意若未来某个文件移除了 from __future__ import annotationsShapeKey 被用于运行时(非类型注解),则需重新评估导入位置。

直接影响:修复 CPU Xeon 测试套件的 CI 崩溃,使 test_server_args.py 从 1 failed/63 passed 变为 64 passed。不影响任何功能逻辑,不改变用户可见行为。团队:减少 CI 噪音,提升开发效率。

极低回归风险 入口导入路径修正

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论