会话、超时与中止路径#
这章解决什么问题#
前两章把一条请求怎样进入系统、怎样回包和怎样收尾讲清楚了,但还留下一个很现实的问题:如果请求不是一次性的,而是 session 里的连续交互,或者它超时、被替换、被 abort,会发生什么?这部分如果不补,request lifecycle 仍然只覆盖了“理想路径”,而没有覆盖工程系统真正必须面对的异常与控制路径。
因此,这一章不是附加边角料,而是 request lifecycle 的第三层厚度。因为一个真正可用的 runtime,不只要能处理正常请求,还要能处理“不该继续跑的请求”。
session 让请求不再是彼此独立#
python/sglang/srt/managers/session_controller.py 暴露出一个很明确的事实:一旦引入 session,系统就不能再把每条请求都当成完全独立个体。Session、RequestSessionConfig、append / replace 相关逻辑,意味着后来的请求可能会依赖前面的状态,也可能试图覆盖它。
这也是为什么 session 逻辑值得单独成章。它改变的不是某个局部 API,而是 request lifecycle 的假设:一条请求不再总是“独立进入、独立完成”,而可能站在已有会话链上继续推进。
为什么 streaming session 的约束更严格#
session_controller.py 里有一组很值得注意的 abort 条件,例如 streaming session 不支持 replace,不支持 offset 等。这类限制说明:当系统已经在持续向调用方输出时,再去修改这条请求的“语义位置”会显著增加一致性成本。
从工程角度看,这种限制并不奇怪。因为 streaming 本来就要求状态持续向外部暴露,一旦中途再允许大幅改写 session 上下文,系统不仅要更新内部 request chain,还要重新解释调用方已经看到的那部分输出。很多看似“为什么不支持”的限制,背后其实都是为了让请求状态和外部观察保持一致。
timeout 和 abort 为什么属于生命周期问题#
timeout 和 abort 经常被误写成“服务治理细节”,但它们其实直接定义了一条请求何时算真正结束。比如 PrefillDelayer 会产生 wait_timeout 一类理由;SessionController 也会在某些条件下直接把新请求标记为 abort。只要这些路径存在,request lifecycle 就不再只是“从入口到输出”的线性流程,而是一张带分叉的状态图。
这类分叉之所以值得读者关心,是因为它们常常决定最难排查的问题:为什么请求没有结果、为什么会话 append 失败、为什么某条请求被系统提前终止。只要你脑子里还只有正常路径,遇到这些现象时就会极其难查。
一个更贴近异常路径的图#
flowchart TD
A["新请求 / 会话请求"] --> B["SessionController / TokenizerManager"]
B --> C{"合法 session 状态?"}
C -->|否| D["abort / reject request"]
C -->|是| E["送入 scheduler"]
E --> F{"等待中超时?"}
F -->|是| G["wait_timeout / output_reason"]
F -->|否| H["正常进入 batch"]
H --> I["detokenize / response assembly"]
I --> J{"streaming session still valid?"}
J -->|否| D
J -->|是| K["finished / state cleanup"]这张图补的是“主链之外的合法分叉”。和前面那张请求时序图相比,它多解释了两件事:session 让请求会受到已有状态约束,而 timeout / abort 会把生命周期提前截断。
调试时先看哪里#
如果现象是“session append / replace 行为不符合预期”,优先看 session_controller.py 的约束判断,而不是先回头怀疑 scheduler。因为这类问题常常在请求进入 batch 之前就已经被裁掉了。
如果现象是“请求没有真正进入运行批次就结束了”,则更适合先追 wait_timeout、abort reason、finished reason 这类状态标签,而不是只盯着模型或前向执行。很多生命周期问题其实在系统决定“不让它继续跑”的那一刻就已经定型了。
本章对应哪些代码路径#
这一章最重要的锚点包括 python/sglang/srt/managers/session_controller.py、python/sglang/srt/managers/prefill_delayer.py、python/sglang/srt/managers/schedule_batch.py 中的 finished_reason / request state 相关路径,以及 test/manual/test_tokenizer_manager.py 这类与 ReqState、crash dump、文本缓冲相关的测试材料。
小结#
一条请求真正完整的生命周期,不只包括“怎样成功跑完”,也包括“在哪些条件下会被拒绝、超时或中止”。把这层补进来之后,request lifecycle 才更接近真实运行系统,而不是一张永远顺利完成的示意图。
叶王 © 2013-2026 版权所有。如果本文档对你有所帮助,可以请作者喝饮料。