fix: 插件增量重载 + clawhubadapter ipcGoroutine 优雅退出

- Registry.Reload 改为增量: 对比插件入口文件(plugin.so/main.lua) SHA256, 仅重载有变更的插件, 未变更保持运行, 消除 plgreload 触发全量 StopAll+Load 导致的重复加载与内置插件状态错乱
- Registry 新增 pluginHashes 记录 + pluginEntryHash 辅助
- clawhubadapter.ipcGoroutine 无退出条件导致重载后旧 goroutine 永久残留(线程累积): 增加 stopCh/stopOnce, Stop() 关闭, ipcGoroutine 用 select 监听退出
- 新增 TestRegistryIncrementalReload 验证无变更跳过/变更重载
This commit is contained in:
JianFeeeee
2026-08-17 08:53:39 +08:00
parent e43b7aa216
commit 2338f3f4f3
3 changed files with 145 additions and 7 deletions

View File

@ -53,6 +53,9 @@ type Plugin struct {
sdk *sdk.PluginSDK
dispatcher *RegistryDispatcher
httpClient *http.Client
stopCh chan struct{}
stopOnce sync.Once
}
// pluginSingleton 内核单例引用Start 时设置),供 SendToChannel/ChannelSender 使用
@ -65,6 +68,7 @@ func New(name, skillsDir string) *Plugin {
}
return &Plugin{
name: name,
stopCh: make(chan struct{}),
skillsDir: skillsDir,
simulatorDir: sd,
dispatcher: NewDispatcher(),
@ -300,10 +304,14 @@ func (p *Plugin) ipcGoroutine(s *sdk.PluginSDK) {
ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop()
for range ticker.C {
p.mu.Lock()
simDir := p.simulatorDir
p.mu.Unlock()
for {
select {
case <-p.stopCh:
return
case <-ticker.C:
p.mu.Lock()
simDir := p.simulatorDir
p.mu.Unlock()
if simDir == "" {
continue
}
@ -339,6 +347,7 @@ func (p *Plugin) ipcGoroutine(s *sdk.PluginSDK) {
}
os.Remove(reloadPath)
}
}
}
}
@ -1247,6 +1256,10 @@ func (p *Plugin) loadSidecar(s *sdk.PluginSDK, dir, name string) error {
func (p *Plugin) Stop() error {
p.mu.Lock()
defer p.mu.Unlock()
// 关停 ipcGoroutinestopCh避免重载后旧 goroutine 残留导致线程累积
p.stopOnce.Do(func() {
close(p.stopCh)
})
for _, sp := range p.sidecars {
sp.Close()
}