Prhub

#30063 [refactor] Add a read-through server_args accessor to RuntimeContext (stack 1/15)

原始 PR 作者 ch-wan 合并时间 2026-07-04 17:19 文件变更 2 提交数 1 评论 1 代码增减 +66 / -3

执行摘要

为 RuntimeContext 添加 server_args 访问器

PR title 和 body 表明这是声明式配置解析栈(declarative config-resolution stack)的 1/15 部分,目的是为 RuntimeContext 添加一个只读的 server_args 访问器,使新代码能够通过上下文访问器访问配置,同时保持旧的全局 getter 不变,实现渐进式迁移。

值得阅读以理解 read-through 模式的意图和实现方式,但无需深度精读。PR 设计简洁清晰,是 15 层重构栈的良好起点。

讨论亮点

PR 没有 review 评论。

实现拆解

  1. runtime_context.py 中添加 _sa() 惰性导入辅助函数:遵循 _ps()_dp() 的相同模式,在函数内部导入 sglang.srt.server_args 模块,避免模块级导入循环。
  2. 更新 RuntimeContext:添加 server_args 属性(@property),委托给 _sa().get_global_server_args(),返回类型为 ServerArgs(仅在 TYPE_CHECKING 块中导入)。同时更新类文档字符串。
  3. 添加模块级 get_server_args() 函数:直接委托给 _CONTEXT.server_args,提供更直接的访问路径。
  4. 新增测试类 TestServerArgsReadThrough:验证三个契约:
    • test_delegates_to_global_getter:通过 mock 确保委托到全局 getter。
    • test_identity_with_global_getter:通过实际设置全局变量验证返回的是同一对象。
    • test_pre_publish_error_passes_through:确保未发布时的 ValueError 能正确透传。
文件 模块 状态 重要度
python/sglang/srt/runtime_context.py 运行时上下文 modified 7.7
test/registered/unit/test_runtime_context.py 运行时上下文 modified 6.89

关键符号

_sa RuntimeContext.server_args get_server_args

关键源码片段

python/sglang/srt/runtime_context.py core-logic

核心变更文件:新增惰性导入 `_sa()`、`RuntimeContext.server_args` 属性和模块级 `get_server_args()` 函数,实现了对全局 ServerArgs getter 的只读委托。

# python/sglang/srt/runtime_context.py# ... 文件头部保持不变 ...from typing import TYPE_CHECKING, Anyif TYPE_CHECKING:
    from sglang.srt.server_args import ServerArgs # 仅用于类型标注,避免运行时循环导入# 已有的惰性导入函数
def _ps():
    from sglang.srt.distributed import parallel_state
    return parallel_statedef _dp():
    from sglang.srt.layers import dp_attention
    return dp_attention# 新增的惰性导入函数:与 _ps() / _dp() 相同模式
def _sa():
    from sglang.srt import server_args
    return server_args# ... ParallelContext 类保持不变 ...class RuntimeContext:
    """Container for the structured runtime accessors; exposes ``parallel`` and
    ``server_args``."""
​
    __slots__ = ("parallel",) # server_args 是 property,不占用 slot
​
    def __init__(self, parallel: ParallelContext):
        self.parallel = parallel
​
    @property
    def server_args(self) -> ServerArgs:
        """The process-wide ``ServerArgs``, read through the global getter."""
        # 委托给全局 getter,保证返回同一对象;不缓存,不介入生命周期
        return _sa().get_global_server_args()
​
​
# 模块级单例
_PARALLEL = ParallelContext()
_CONTEXT = RuntimeContext(parallel=_PARALLEL)
​
​
def get_context() -> RuntimeContext:
    return _CONTEXTdef get_parallel() -> ParallelContext:
    return _PARALLEL# 新增的便捷访问函数
def get_server_args() -> ServerArgs:
    """Shortcut to ``get_context().server_args``."""
    return _CONTEXT.server_args
test/registered/unit/test_runtime_context.py test-coverage

新增测试类 TestServerArgsReadThrough,覆盖委托、同一性和错误传播三个关键契约,确保新代码正确性。

# test/registered/unit/test_runtime_context.py# ... 顶部 import 及已有测试保持不变 ...class TestServerArgsReadThrough(CustomTestCase):
    """``server_args`` delegates live to the global getter (read-through, V2a)."""
​
    def test_delegates_to_global_getter(self):
        sentinel = object()
        # 使用 mock 模拟全局 getter,验证新 accessor 正确委托
        with patch(f"{_SA}.get_global_server_args", return_value=sentinel):
            self.assertIs(get_server_args(), sentinel)
            self.assertIs(get_context().server_args, sentinel)
​
    def test_identity_with_global_getter(self):
        import sglang.srt.server_args as server_args_module
​
        # Identity (not equality) is the contract; publish accepts any object.
        sentinel = object()
        saved = server_args_module._global_server_args
        try:
            server_args_module.set_global_server_args_for_scheduler(sentinel)
            # 验证新 accessor 与旧全局 getter 返回同一对象
            self.assertIs(
                get_server_args(), server_args_module.get_global_server_args()
            )
            self.assertIs(get_server_args(), sentinel)
        finally:
            server_args_module._global_server_args = saved
​
    def test_pre_publish_error_passes_through(self):
        import sglang.srt.server_args as server_args_module
​
        saved = server_args_module._global_server_args
        server_args_module._global_server_args = None # 模拟未发布状态
        try:
            with self.assertRaises(ValueError) as cm:
                get_server_args()
            # 验证错误消息与原始 getter 完全一致
            self.assertEqual(
                str(cm.exception), "Global server args is not set yet!"
            )
        finally:
            server_args_module._global_server_args = saved

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

风险极低。此 PR 是纯添加性的(purely additive),只新增了 _sa 函数、RuntimeContext.server_args 属性和 get_server_args() 函数,没有修改任何现有代码逻辑。所有旧调用点保持不变。测试覆盖了委托、同一性和错误透传三个关键契约。

影响范围:仅影响 RuntimeContext 和新增测试文件。用户不可见,系统行为无变化。
影响程度:低。这是声明式配置重构的基础步骤,为后续 PR 提供基础设施。

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论