会话与并发:sessionKey / lane / queue
这一章关注“排队系统”:如果会话隔离做不好,最直接的症状就是串线、乱序、上下文污染。
你需要掌握的要点
sessionKey如何设计才能在群组/频道/私聊之间保持稳定隔离- 为什么同一
sessionKey必须串行(避免并发写会话导致历史竞争) - 为什么还需要全局并发上限(保护模型/工具/IO 资源)
双层排队模型:session 保序 + global 限流
你可以把它理解成“局部有序 + 全局门控”:
- 外层:按
sessionKey进入 session lane(同会话严格串行) - 内层:按全局 lane 进入 global queue(限制同时运行的任务数)
这能同时解决两件事:
- 同会话不乱序(避免并发写会话历史)
- 全局并发可控(避免模型/工具/IO 资源被打爆)
Lane 状态机:队列、并发、告警与恢复
建议你在实现里显式保留这些机制:
- maxConcurrent:lane 并发上限(默认 1)
- warnAfterMs/onWait:排队太久只告警不取消,让上层可观测
- generation:热重启/异常恢复时递增 generation,防止旧任务 finally 回写污染新状态
clear 与 reset 的边界
clear:只取消“未开始”的队列任务,不影响已在执行中的任务resetAllLanes:用于进程内热重启等场景,强制清空 active 并通过 generation 让旧回调失效,然后继续 drain 积压队列
Probe lane:探针失败应静默
认证探针等任务本质是“试错”,失败是预期行为。 对 probe lane 的失败建议静默处理,避免产生误导性错误日志。
与运行注册表的配合:steer/abort 必须可预测
如果你支持在 run 进行中插入 follow-up(steer),建议做到:
- 只在 streaming 且非 compacting 时接受 queueMessage
- 清理 active run 时做 handle 匹配,避免竞态误删
相关入口:
入口:
最小可验证行为
- 同一
sessionKey两条消息不会乱序。 - 不同会话可以并行执行,且不会互相污染上下文。
- 你能从
runId反查到这次执行对应的会话归属(用于排障与审计)。
失败场景与排障入口
- 乱序/串线/上下文污染:优先确认
sessionKey是否稳定且隔离(群聊/频道/私聊不要共用同一个 key),再确认 session lane 是否串行(maxConcurrent=1)。入口:会话管理 / 队列与 Lane。 - 吞吐突然下降:检查 global lane 并发上限是否过低,或某类任务(例如 Cron/Subagent)是否占满并发;用 日志 结合
runId看排队与执行耗时。 - 重启后队列“僵死”:确认 reset/generation 机制是否生效,避免旧任务 finally 回写污染新状态(参见 生命周期与运维)。
验收清单(建议做并发压测)
- 同一 session 连续发送多条消息,回复顺序稳定。
- 两个 session 可以并发执行,且不会互相阻塞到“完全串行”。
- reset 后不会出现队列僵死(积压任务能继续 drain)。
- 旧 finally 不会污染新状态(generation 机制生效)。
读源码入口(可选)
src/agents/pi-embedded-runner/lanes.tssrc/process/command-queue.tssrc/gateway/server-lanes.tssrc/gateway/server-session-key.tssrc/config/sessions/session-key.ts