feat(gateway,loop): 忙时并行回合基础管线(I1′ 有条件放宽)
- turnId 由编排器生成、loop Run 复用(硬前提:否则 turn_begin 与流帧各铸一个,客户端两级分桶立即失配) - StateSink 增带 turnId 的变体(未接线时退化为现签名,不丢状态帧) - 上行 chat.parallel(WS chat 帧 + REST 三入口同形;省略 = 逐字不变) - 单会话额度默认 2 / 硬上限 3 / <2 关闭;额度满或未声明 ⇒ 落回既有排队语义 - I1′:checkpoint 归属、历史配对、忙态计数三处从会话级单例升为路级 - session_idle 收紧为「所有在途路收尾且 pending 空」(仅并行时生效;单路逐字不变) - 预留接口(形状定死、无实现无接线):tool/legfile.go 的 FileClaimer / ErrFileBusy / WithLegID - 顺手修一个真 bug:并行路 ctx 派生自提交请求作用域,REST 同步入口一写响应就把它连坐杀死(改 context.WithoutCancel 派生) - 23 个新用例(含 -race -count=3);变异 6 条(turnId 复用 / idle 时点 / 并行升级 / checkpoint 键 / 编排器交 id / pending_ack reason) - 契约变更点 10 条待监工升 v0.65(本人未改 Docs/**)
This commit is contained in:
1 parent
7d2ff74cfc
commit
89e13cf53d
23 files changed
+1921
-275
No files matched your search
@@ -186,13 +186,13 @@ func candidateSeqs(cs []steerCandidate) map[uint64]bool {
|
||||
}
|
||||
|
||||
// pendingSnapshot 在状态锁下取该会话待处理队列的一份副本(世代不符时返回 nil:
|
||||
// 那份队列已不属于本回合,例如被中断清空或被更新的顶层回合取代)。取副本而不是
|
||||
// 那条路已失效,例如被打断、被取代或会话已清空)。取副本而不是
|
||||
// 持锁做转录读取,是为了不让有界存储读取堵住 Submit。
|
||||
func (o *Orchestrator) pendingSnapshot(sessionID string, gen uint64) []pendingMsg {
|
||||
o.mu.Lock()
|
||||
defer o.mu.Unlock()
|
||||
st := o.states[sessionID]
|
||||
if st == nil || st.gen != gen || len(st.pending) == 0 {
|
||||
if o.legLocked(st, gen) == nil || len(st.pending) == 0 {
|
||||
return nil
|
||||
}
|
||||
return append([]pendingMsg(nil), st.pending...)
|
||||
@@ -202,9 +202,14 @@ func (o *Orchestrator) pendingSnapshot(sessionID string, gen uint64) []pendingMs
|
||||
// 被第二个回合再答一遍)。它按 pendingMsg.seq 认领,因此即便队列在同一时刻被追加
|
||||
// (只会加在队尾)或被中断清空,也绝不会误删别的消息。
|
||||
//
|
||||
// 返回 false 表示这次认领**没有生效**(队列里已无这些序号,或世代已被中断/更新的
|
||||
// 顶层回合取代)——调用方此时必须放弃注入:否则这条消息会被本回合与那条新路径各答
|
||||
// 一次。它必须在把消息交给循环**之前**调用。
|
||||
// 返回 false 表示这次认领**没有生效**(队列里已无这些序号,或本路已失效
|
||||
// ——被打断、被取代)。调用方此时必须放弃注入:否则这条消息会被本回合与那条
|
||||
// 新路径各答一次。它必须在把消息交给循环**之前**调用。
|
||||
//
|
||||
// 多路口径(design/15 §2.5.2 I2):认领仍只走这一把锁与这一套序号,因此
|
||||
// 「新起的第 2 路」与「在飞路的下一个 steer 边界」抢同一条消息时也只有一个赢家
|
||||
// ——升级路径本就不把消息放进 pending(它直接登记为一条新路),而 steer 只能
|
||||
// 认领 pending 里的条目,两者不可能同时拿走同一条。
|
||||
func (o *Orchestrator) consumePending(sessionID string, gen uint64, seqs map[uint64]bool) bool {
|
||||
if len(seqs) == 0 {
|
||||
return false
|
||||
@@ -212,7 +217,7 @@ func (o *Orchestrator) consumePending(sessionID string, gen uint64, seqs map[uin
|
||||
o.mu.Lock()
|
||||
defer o.mu.Unlock()
|
||||
st := o.states[sessionID]
|
||||
if st == nil || st.gen != gen {
|
||||
if o.legLocked(st, gen) == nil {
|
||||
return false
|
||||
}
|
||||
kept := make([]pendingMsg, 0, len(st.pending))
|
||||
|
||||
Reference in new issue
Block a user