Prhub

#31813 runtime_context: record the publishing process role

原始 PR 作者 ch-wan 合并时间 2026-07-22 16:17 文件变更 8 提交数 1 评论 6 代码增减 +183 / -39

执行摘要

为配置发布添加进程角色记录

随着结构化 RuntimeContext 配置 API 的推进,需要记录配置是由哪个进程角色发布的(scheduler/tokenizer/encoder等),以便未来实现更精细的配置隔离和审计。同时,遗留的 setter 需要成为角色特定的 shim,为从全局函数迁移到命名空间访问器铺平道路。该 PR 是 stacked series 的一部分,行为保持,仅添加角色记录。

该 PR 是结构化配置 API 系列的重要一环,值得精读,尤其是 _ConfigBag__slots__ 移除和 torch.compile 追踪支持的设计决策。自动化 review 提出的风险点需要在后续 PR 中跟进。建议关注同一系列的其他 PR(#31812、#31814-#31817)以理解完整上下文。

讨论亮点

自动化 review 提出了 5 条建议:

  • P1-更新测试合同:分离 tokenizer setter 后,现有测试 test_tokenizer_alias_is_same_function 将失败,需要更新。
  • P1-降低 ratchet 计数:移除两个调用点后,需将 _RATCHETS 从 5 降到 4。
  • P1-隔离 draft 配置覆盖preserve_config 只保存引用,draft 构建中触发的 declare_load_time_override 可能修改目标 ServerArgs,导致恢复后配置袋与源不一致。
  • P2-清除角色:建议 set_server_args 清除 _publish_role,以免遗留 setter 后角色漂移。
  • P1-延迟自引用注解_set_sub 中使用了 _ConfigBag 作为类型注解,在 Python 3.10-3.13 中会导致 NameError,需启用 from __future__ import annotations 或使用字符串引用。
    这些建议未在 PR 中得到作者公开回应,部分风险可能由系列其他 PR 解决。

实现拆解

  1. python/sglang/srt/runtime_context.py 中新增 publish 函数,接受 server_argsrole 和可选的 hf_config,调用 get_context().set_server_args(server_args) 并记录 _publish_role;新增 publish_role 函数返回当前角色。同时新增 preserve_config 上下文管理器,快照并恢复整个配置生命周期(服务器参数和配置袋)。
  2. 重构 _ConfigBag 类:移除 __slots__,将叶子节点和子 bag 作为真实实例属性存储(通过 __dict__),使得 torch.compile / Dynamo 可以追踪属性读取(如 get_exec().comm.enable_symm_mem);添加 _set_sub 方法注册子 bag;修改 _set 方法同时更新书签字典和实例属性;修改 override 上下文管理器使用 _set 以确保一致性。
  3. python/sglang/srt/server_args.py 中,将 set_global_server_args_for_tokenizerset_global_server_args_for_scheduler 的函数别名改为独立函数,内部调用 publish(server_args, role="tokenizer");同时更新 set_global_server_args_for_scheduler 的文档字符串并改为调用 publish(server_args, role="scheduler")
  4. 在各个进程入口点添加 publish 调用:scheduler.py::run_scheduler_process 发布角色 "scheduler",data_parallel_controller.py::run_data_parallel_controller_process 发布角色 "scheduler",encode_server.py 发布角色 "encoder",expert_backup_manager.py 发布角色 "expert_backup"。
  5. python/sglang/srt/speculative/draft_worker_common.py::build_draft_tp_worker 中,将手动备份恢复替换为 get_context().preserve_config() 上下文管理器,使得快照包含所有的后发布覆盖,避免因重新发布而丢失覆盖。
  6. 测试文件 test/registered/unit/test_runtime_context_override.py 新增三个测试用例覆盖角色记录:验证 publish 记录角色、遗留 shims 记录角色、reset_context 清除角色。
文件 模块 状态 重要度
python/sglang/srt/runtime_context.py 运行时上下文 modified 8.66
python/sglang/srt/server_args.py 服务器参数 modified 6.73
python/sglang/srt/speculative/draft_worker_common.py 推测解码 modified 6.25
test/registered/unit/test_runtime_context_override.py 配置测试 modified 6.16
python/sglang/srt/managers/scheduler.py 调度器 modified 5.44
python/sglang/srt/managers/data_parallel_controller.py DP 控制器 modified 5.19
python/sglang/srt/disaggregation/encode_server.py 编码服务器 modified 4.73
python/sglang/srt/elastic_ep/expert_backup_manager.py 专家备份 modified 4.73

关键符号

publish publish_role preserve_config _set_sub set_global_server_args_for_scheduler set_global_server_args_for_tokenizer

关键源码片段

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

核心变更文件:新增 publish/publish_role/preserve_config 函数,重构 _ConfigBag 以支持 torch.compile 追踪属性,变更配置发布机制。

# _ConfigBag : resolved-config namespace bag, read-only by bare assignment.
# Leaves are stored as real instance attributes (in __dict__ ) so that
# torch.compile can trace attribute reads without graph-breaking.def _set(self, name: str, value: Any) -> None:
    '''Internal write that bypasses the read-only guard.
    Updates both the bookkeeping map and the real attribute (traceable read).'''
    object.__getattribute__(self, '_fields')[name] = value
    object.__setattr__(self, name, value) # real attribute for traceabilitydef _set_sub(self, name: str, sub: '_ConfigBag') -> None:
    '''Register a nested bag as both a bookkeeping entry and a real
    attribute (so ``bag.sub`` is a plain, traceable attribute load).'''
    object.__getattribute__(self, '_subs')[name] = sub
    object.__setattr__(self, name, sub) # now torch.compile can see it@contextmanager
def override(self, **kwargs):
    '''Scoped, transactional test-only override of this bag's own leaves.
    Keys validated before any write; restored on exit.'''
    fields = object.__getattribute__(self, '_fields')
    unknown = set(kwargs) - set(fields)
    if unknown:
        path = object.__getattribute__(self, '_path')
        raise ValueError(f'unknown config leaf for {path!r}: {sorted(unknown)}')
    saved = {name: fields[name] for name in kwargs}
    for name, value in kwargs.items():
        self._set(name, value) # uses traceable _set
    try:
        yield self
    finally:
        for name, value in saved.items():
            self._set(name, value) # restore via traceable path
python/sglang/srt/server_args.py core-logic

将 set_global_server_args_for_tokenizer 从别名变为独立函数,为遗留 setter 分配明确角色,是配置迁移的关键一步。

# Legacy publish shims — prefer runtime_context.publish(server_args, role=...)
# in new code. Imports are in-function to keep cycle-free at import time.
def set_global_server_args_for_scheduler(server_args: ServerArgs):
    '''Legacy publish shim (role=scheduler).'''
    from sglang.srt.runtime_context import publish
    publish(server_args, role='scheduler')def set_global_server_args_for_tokenizer(server_args: ServerArgs):
    '''Legacy publish shim (role=tokenizer). Not aliased to the scheduler shim:
    the process role differs.'''
    from sglang.srt.runtime_context import publish
    publish(server_args, role='tokenizer')

评论区精华

更新遗留别名合同测试 测试

自动化建议指出定义独立的 tokenizer setter 后,测试 test_tokenizer_alias_is_same_function 将无条件失败,需要更新以反映函数不再相同。

结论:未在 PR 中处理,可能影响 CI · 待处理

降低遗留 setter ratchet 计数 测试

建议将 _RATCHETS 从 5 降到 4,以匹配调用点减少。

结论:未处理,但可能在其他 PR 中调整 · 待处理

隔离 draft 构建时配置覆盖 设计

preserve_config 只保存引用,若 draft 构建触发 declare_load_time_override 会修改目标 server_args,导致恢复后配置袋与原始 server_args 不一致。

结论:设计权衡,可能需要深拷贝保护 · 待处理

set_server_args 应清除角色 设计

建议 set_server_args 清除 _publish_role,以免遗留 setter 后角色残留旧值。

结论:未实现,可能导致角色漂移 · 待处理

自引用注解延迟评估 正确性

在 Python 3.10-3.13 中,_set_sub 使用 _ConfigBag 作为类型注解会导致 NameError,需要启用 from __future__ import annotations 或使用字符串引用。

结论:代码中尚有自引用注解,若未启用推迟评估则会导致导入崩溃 · 待处理

风险与影响

  • 核心配置路径变更_ConfigBag__slots__ 切换到 __dict__,影响内存和属性查找,但换来 torch.compile 可追踪性,属于设计权衡。
  • 测试覆盖缺口:自动化建议指出两个现有测试需要更新(tokenizer 别名测试和 ratchet 计数测试),若未更新会导致 CI 失败。
  • 配置隔离风险preserve_context 仅保存引用,在 draft 构建中如果目标 ServerArgs 被突变,恢复时可能出现配置袋与源不一致。
  • 角色一致性set_server_args 不清除角色,可能导致遗留 setter 后角色仍残留旧值,违反预期。
  • 兼容性set_global_server_args_for_tokenizer 从别名变为独立函数,任何依赖 is 比较的代码可能失败。
  • 自引用注解:若未启用 from __future__ import annotations,在 Python 3.10-3.13 上导入 runtime_context 会抛出 NameError
  • 用户影响:无直接用户可见变更,行为保持。
  • 系统影响:配置发布机制增加了角色追踪,为未来配置隔离和审计奠定基础。_ConfigBag 的变更可能影响所有通过命名空间读取配置的代码(如 get_exec().comm.enable_symm_mem),使其在 torch.compile 下不再图打断。
  • 团队影响:开发者需要在新代码中使用 publish(server_args, role=...) 替代直接调用 set_server_args。遗留 setter 仍然可用但会被逐步淘汰。
  • 影响范围:中。涉及 8 个文件,包括运行时上下文核心、服务器参数、调度器、DP 控制器、编码服务器、专家备份管理器和 draft 工作线程。
核心路径变更(配置机制) 测试合同未同步更新 配置隔离风险(draft 构建) 角色一致性未保证 自引用注解兼容性 遗留 setter 行为变化

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论