mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-07 09:47:23 +00:00
用户指出的设计错误:**一个插件 = 一个 Lua VM = 一个调度器**。而 Phase 4
(4d1407b)给定时任务开了一个**私有 VM**,于是:
定时任务 refresh_token 写 plugin.state.token → 写进私有 VM 的副本
请求钩子 读 plugin.state.token → 读主 VM 的值
轮换"成功"了,对实际流量完全无效;而且私有 VM 绕过状态持久化,token 连
磁盘都到不了。这直接违背这个功能存在的理由。
## 修正
PluginRuntime 不再持有 Lua 状态。任务通过 p.state + p.mu 运行 —— 与请求
钩子**同一个 VM、同一把锁**:
- 任务写入立即可见于钩子(TestTaskWriteIsVisibleToHooks 锁死这一点)
- 任务写入经 markDirtyLocked 走同一套持久化
- 跨插件仍并行(每插件各自 VM、各自锁)
## 由此产生的行为(有意为之,非缺陷)
- 某插件的长任务会排在**它自己**的钩子前面(同一 Lua 栈,一次一个调用者)
- 卡死处置随之改变:不再"抛弃 VM 重建"(那会丢掉累计状态——计费总额、
签到历史,正是插件存在的意义),而是**停用该插件**:
- checkWedged 超过 wedgedAfter(10min) 置 disarmed
- Fire 对 disarmed 插件快速失败并记 hook_errors(否则请求会排在永不释放
的锁后面永久挂起——比停用更糟)
- Unload 检测 InFlight:有任务在跑时不取 p.mu(会永久挂起)、不 Close
状态(Lua C 层 use-after-free 直接 abort)。泄漏这一个状态是有界的,
比崩溃好。
- maxAbandons/抛弃计数因此删除:没有"重生"了,熔断由 disarmed 承担
## 测试(10 个)
主断言从"任务跑过"改为"**任务的写入对请求路径可见**"—— 旧实现会在这里
失败。另含:无触发自执行/无 schedule 无运行时/解析/at 下次触发/错误隔离/
卸载停 goroutine/卡死停用+钩子快失败/健康任务不误判/8 插件并发各自调度。