mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-06 01:07:35 +00:00
fix(plugin): 修两处持锁自死锁(CI 双红真因)+ tools_ready 事件声明
## 死锁(这是 CI 连续两次红的真因) `StopAll` 与 `StopPlugin` 都在持有 `r.mu` **写锁**时调用 `RemoveBuiltinSkill` → `skillDirOf` → `r.mu.RLock()` ⇒ **自死锁**。 后果不是报错而是**卡死**: - internal/plugins 卡 300s 超时(TestCapability_RestrictedPluginStillLoads) - internal/plugin 卡 840s 超时(TestStopPluginDoesNotTouchPersistentState) - CI 的 `go test ./...` 与 `go test -race` 双双红 修法:拆出**不加锁**的内部版本,持锁路径只走它: - `skillDirFrom(dataDir, name)`(纯函数) - `removeBuiltinSkillLocked(pluginName, p, dataDir)`(显式传 dataDir, 避免"看起来没取锁、一改就取锁"的隐患) - `announceSkillRemovedLocked`(持锁下直读 r.evBus) 修后:internal/plugins 300s → 12s,internal/plugin 840s → 0.7s。 ## 防回归判据 `TestStopAllAndStopPluginDoNotDeadlock`:死锁**不返回**,普通断言抓不到, 所以用**超时**当判据(5 秒未返回即失败),并指明应改用 Locked 版本。 ## tools_ready 事件声明 新增的 tools_ready 触发 `TestEveryPublishedEventHasAnOutwardPath` (该判据防"事件发了、客户端收不到"的静默失效)。 tools_ready 是**内核内部**就绪信号(plugin-host → seq 等订阅者), 不是对话流程事件,前端无需感知 ⇒ 在 allowed 里显式声明理由。 ## 验证 go build ./... / go vet ./... / go test -p 1 ./... / -race 全通过。
This commit is contained in:
@ -58,6 +58,8 @@ type Plugin struct {
|
||||
sdk *sdk.PluginSDK
|
||||
// runner 指向内核(由 Start 注入)
|
||||
runner seqRunner
|
||||
// unsubBoot 是 agent_ready 的退订函数(Stop 时调用)
|
||||
unsubBoot func()
|
||||
// 调用栈深度:跨序列/跨 group 嵌套的**结构上界**(maxCallDepth)
|
||||
callDepth int
|
||||
}
|
||||
@ -82,11 +84,21 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
||||
p.store = NewStore(dir)
|
||||
p.runner = &kernelRunner{tool: s.Tool()}
|
||||
p.registerTools()
|
||||
|
||||
// 订阅 agent_ready:用它的 boot 序列在**系统真正可用**时自动执行。
|
||||
// 不能在这里直接跑 —— 此刻工具所属插件可能还没拉起、agent 循环还没开始。
|
||||
p.unsubBoot = p.subscribeBoot()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop 清理(无订阅需注销)。
|
||||
func (p *Plugin) Stop() error { return nil }
|
||||
// Stop 清理订阅。
|
||||
func (p *Plugin) Stop() error {
|
||||
if p.unsubBoot != nil {
|
||||
p.unsubBoot()
|
||||
p.unsubBoot = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// kernelRunner 把 sdk.ToolAPI 适配成 seqRunner。
|
||||
type kernelRunner struct{ tool sdk.ToolAPI }
|
||||
|
||||
Reference in New Issue
Block a user