Skip to content

[Bugfix][Tokenizer] 回移上游 #41911:批量请求 rid 冲突时不再留下孤儿 rid_to_state - #37

Merged
lihenga merged 1 commit into
lihenga:feature/optimize_mainfrom
lzb16:lzb/pick-upstream-41911-rid-state
Oct 20, 2026
Merged

lihenga merged 1 commit into
lihenga:feature/optimize_mainfrom
lzb16:lzb/pick-upstream-41911-rid-state

Conversation

@lzb16

@lzb16 lzb16 commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

Motivation

批量请求(rid 为列表)中,如果排在后面的某个 rid 与一个仍在处理中的请求重名,_init_req_state 会先把前面的 rid 逐个写进 rid_to_state,检查到重名时才抛出 Duplicate request ID detected。而 _init_req_state 在 generate_request 的 try 之外调用,前面已写入的状态不会被回滚,形成孤儿:

  • 这些 rid 在重启前都不能再用,再发会一直返回 Duplicate request ID detected;
  • 每个孤儿保留整条子请求对象(含 prompt),随异常批量请求的次数只增不减;
  • 只向主进程发 SIGTERM 时,优雅退出要等 rid_to_state 清空,会一直等待。

我们在泄漏测试中实测复现:每轮构造 3 次,P 侧 tokenizer 的孤儿数 0 → 3 → 6,不回收。

上游 sgl-project/sglang 已于 10-12 修复:#41911「Make tokenizer request-state initialization atomic」(提交 28621739fc)。本 PR 将其回移到 feature/optimize_main。

Modifications

  • python/sglang/srt/managers/tokenizer_manager.py:与上游逐行相同。先检查整批 rid(与在途请求或批内重名都拒绝),全部通过后再构造 ReqState,最后一次性 update 进 rid_to_state;构造过程中抛异常也不会留下部分状态。
  • test/registered/unit/managers/test_tokenizer_manager_rid_cleanup.py:带入上游新增的 TestInitReqStateAtomicity,按本分支的测试辅助函数调整:
    • 补 patch 导入;
    • 去掉 LoRA 引用计数相关断言(本分支 _make_tm_for_generate 没有 enable_lora 参数,TokenizerManager 没有 _release_lora_once),用例改名为 test_live_collision_preserves_map,重名位置 0/1/2、Generate/Embedding 两种请求的检查保留;
    • 去掉 ReqState.dispatched 断言(本分支 ReqState 无此字段)。
  • 单个提交,作者保留为上游原作者,提交信息含 cherry picked from commit 28621739fc6e8084b59f0b02178413f993e35afb 和回移说明。

Accuracy Tests

VERIFIED:CPU 单测,Docker 容器(python 3.10.12、pytest 9.1.1),PYTHONPATH 指向本分支源码,未安装包、未启动服务。

PYTHONPATH="$PWD/python" python -B -m pytest -q -p no:cacheprovider \
  test/registered/unit/managers/test_tokenizer_manager_rid_cleanup.py
  • 修复后:24 passed(含 20 个子测试)。
  • 修复前(父提交的 tokenizer_manager.py + 同一测试文件):11 failed、23 passed。批内第 2、3 项与在途请求重名的用例失败(第 1 项重名本来就不会留下孤儿,通过),构造过程中抛异常的用例也失败。
  • black 26.1.0、isort 7.0.0、ruff 0.15.1(--select=F401,F821,UP037):测试文件通过;tokenizer_manager.py 第 1220 行附近有一处 black 格式问题,修改前就存在,与本 PR 无关,未改动。

UNTESTED:未编包,未做服务级端到端复测(构造批量请求重名后再用同一 rid 请求、SIGTERM 优雅退出)。

Speed Tests and Profiling

未运行;改动只涉及请求登记时的 rid 检查顺序,不涉及模型计算。

Checklist

  • 源码改动与上游 #41911 一致
  • 新增单测在修复前失败、修复后通过
  • 服务级复测

Co-authored-by: Cheng Wan <54331508+ch-wan@users.noreply.github.com>
(cherry picked from commit 2862173)

Backport notes for feature/optimize_main:
- The tokenizer_manager.py change is identical to upstream: validate every
  rid of a (batch) request before inserting any ReqState, so a batch whose
  later rid collides with an in-flight request no longer leaves orphan
  rid_to_state entries (which made those rids unusable and kept graceful
  SIGTERM shutdown waiting forever).
- Tests adapted to this branch's helpers: import `patch`; drop the LoRA
  adapter-refcount assertions (`_make_tm_for_generate` here has no
  `enable_lora`, and TokenizerManager has no `_release_lora_once`); drop the
  `ReqState.dispatched` assertion (field not present on this branch).
- test_tokenizer_manager_rid_cleanup.py: 24 passed with this change; on the
  parent commit the new cases fail (11 failed), including rid collisions at
  batch positions 1 and 2.
@lihenga
lihenga merged commit d41ef9d into lihenga:feature/optimize_main Oct 20, 2026
0 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants