|
|
f33ebee01b
|
test(agent/core): 消除测试对 scheduler.queue 的无锁直读,并加判据防回归
## 起因
offload_test.go 等 4 个文件里有 18 处 `len(s.queue)` / `range s.queue`,
全在锁外。当时**安全**——那些测试用 newRootWithoutSchedulerLoop,
刻意不启 schedulerLoop,所以没有并发写者。
但这个安全性 ① 不由测试自身保证,只由「别改构造函数」这个口头约定保证;
② 一旦有人换成 newRootWith 就变成真竞争,症状是「今天全绿、改一次就炸」。
先确认生产代码没问题:逐处核对 scheduler.go 里 6 个读 s.queue 的函数,
全部在 mu.Lock/RLock 内(takeQueuedInputs/hasRoom/nextRef/armStop/
pendingEvents/takeAllPendingEvents)。所以这是**测试的隐患**,不是核心缺陷。
## 改动
- scheduler.go 新增两个带锁只读访问器:
· queueLen() —— 替代 len(s.queue)
· queueSnapshot() —— 返回浅拷贝,替代 range/索引(拷贝保证 len 与
range 不会在遍历中途变化)
- 4 个测试文件 18 处直读全部改走访问器
- 新增 queue_access_test.go:AST 静态判据,扫所有 *_test.go,
同一函数内出现过 Lock/RLock 即视为持锁(Go 的 defer Unlock 静态难还原,
按函数近似足够保守);命中无锁直读即红
## 判据自检
静态判据最大的失败模式是「根本没抓到东西」,所以带双向自检:
- 正向:注入一处无锁直读 → 必须被抓到
- 反向:注入一处持锁直读 → 必须**不**被报(否则噪声大没人看)
- 真变异:把一处访问器改回 `len(s.queue)` → 红
## 验证
- go build ./... / go vet / go test ./internal/... 全绿
- go test -race ./internal/agent/core/ 无数据竞争
- 部署后:39 插件加载、3 个 multimodal 工具注册、0 panic/fatal
- graph.db integrity ok,blocks 2787 未动
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-10-06 09:22:12 +08:00 |
|
|
|
2be407b7b2
|
feat(scheduler)!: 中断/排队两类别模型 + 插件声明 L1-L3、L4 内核独占
用户澄清推翻了早期设计的三处前提,本提交按新模型重做调度核心(行为有意变化):
1) 类别由注入 API 决定,与通道名无关
- InjectInterrupt* -> TaskInterrupt(带级别,可被严格更高级中断打断)
- InjectText*/InjectInputSync*/内核自循环 -> TaskQueued(无级别,可被任何中断打断)
- 删除按通道名推断的 taskLevel():qq 走 InjectInterruptTextOpts,本就是中断
2) 级别只属于中断
- 插件在 InjectOptions.Priority 声明 L1-L3(空/非法降级 L1,声明 L4 夹到 L3)
- L4 内核独占:新增 raiseKernelInterrupt(panic / selfip);requestKernelPreempt 不夹取
- panic 现在产生一条带 kernel 标记的 L4 中断;L4 自身 panic 不再产生新 L4(防自我放大)
3) 选择结构:四容器固定次序,删除统一比较器
- immediate(抢占者立即运行)-> 中断队列 L4..L1 -> 栈顶(与队头比级别) -> 排队 FIFO
- 删除 pickTaskIndex/taskBefore 与“同级 pending 优先”补丁(根因是抢占者进了队列)
- 中断栈上界改为结构推论 = 4(= 中断级数);删除“超限转 pendingInterrupts”降级
公开 SDK(feature 分支有意新增,纯追加):InjectOptions.Priority + PriorityL1/2/3;
内核 io / proc 桥 / 插件模板同步透传。
设计稿 §2/§3/§4.1/§6.3/§9/§11/§12/§13/§15 按新模型重写。
验收:go build/vet 干净;go test ./... 37 包 ok 0 FAIL;-race 全绿;
e2e(抢占-挂起-恢复)+ 压力(200 排队 + 50 中断,L1/L2/L3 轮转)通过。
|
2026-09-13 07:00:51 +08:00 |
|
|
|
d39e8d8746
|
feat(scheduler): M2 调度器骨架(就绪队列 + 选择函数 + 快照 + 任务级 panic 隔离)
设计依据 docs/zh/input-scheduler-design.md §14 M2。
- 新增 scheduler.go:四级 Level 常量(默认 L1,显式才是特权)、
Task/TaskKind、scheduler(有界队列/running/统计)、纯函数 pickTaskIndex
(排序键 -Level → EnqueuedAt → ID)、schedulerLoop/pumpInbox/executeTask、
DumpScheduler 原子快照
- eventLoop 退场,职责由 schedulerLoop 承担;M2 全部任务为 L1,
因而行为等价于原先的 channel FIFO
- 每任务 panic 隔离(不变量 I6):panic 只失败该任务,调度器存活,
取代原先「重启整个循环」
- Start() 改起 schedulerLoop;interceptLoop 暂不动(M3 重写)
- 新增 scheduler_test.go:Q1 排序 4 组、Q4 背压、生命周期、K1 panic 隔离、
O1 快照一致性、Level 取值契约
- 验收:agent 全量 + -race 通过
|
2026-09-12 23:49:55 +08:00 |
|