From 9f21346e53e06248f7c1ec76851611e1a9ea899f Mon Sep 17 00:00:00 2001 From: HuaiYJ Date: Mon, 24 Aug 2026 16:21:14 +0800 Subject: [PATCH] fix: snapshot plugins before manager stop --- internal/plugin/manager.go | 20 +++++++++++++++++--- internal/plugin/manager_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/internal/plugin/manager.go b/internal/plugin/manager.go index fecc8c3..f8d2d0f 100644 --- a/internal/plugin/manager.go +++ b/internal/plugin/manager.go @@ -176,12 +176,26 @@ func (m *Manager) Stop() { // 关闭schedule m.Cron.Stop() - // 退出所有正在执行的插件 - for _, rp := range m.RunningPlugins { + // 在锁内复制运行列表,在锁外停止进程,避免与清理协程并发读写 map, + // 同时不让可能阻塞的进程停止操作长期占用 Manager.Lock。 + for _, rp := range m.runningPluginsSnapshot() { rp.Stop() } - m.innerCancel() + if m.innerCancel != nil { + m.innerCancel() + } +} + +func (m *Manager) runningPluginsSnapshot() []*RunningPlugin { + m.Lock.Lock() + defer m.Lock.Unlock() + + running := make([]*RunningPlugin, 0, len(m.RunningPlugins)) + for _, rp := range m.RunningPlugins { + running = append(running, rp) + } + return running } // RunPlugin 在独立进程组中拉起插件子进程(Setpgid=true, diff --git a/internal/plugin/manager_test.go b/internal/plugin/manager_test.go index 53fa010..d184e9d 100644 --- a/internal/plugin/manager_test.go +++ b/internal/plugin/manager_test.go @@ -3,12 +3,37 @@ package plugin import ( "os" "path/filepath" + "sync" "testing" "time" "gitee.com/OpenCloudOS/ocmanager/agent/internal/config" ) +func TestManagerRunningPluginsSnapshotConcurrent(t *testing.T) { + mgr := &Manager{RunningPlugins: make(map[string]*RunningPlugin)} + const iterations = 1000 + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + for i := 0; i < iterations; i++ { + mgr.Lock.Lock() + mgr.RunningPlugins["demo"] = &RunningPlugin{Plugin: &Plugin{Name: "demo"}} + delete(mgr.RunningPlugins, "demo") + mgr.Lock.Unlock() + } + }() + for i := 0; i < iterations; i++ { + for _, rp := range mgr.runningPluginsSnapshot() { + if rp == nil { + t.Fatal("snapshot contains a nil running plugin") + } + } + } + wg.Wait() +} + // writePluginYAML 在指定目录下写入一个插件 yaml 文件。 func writePluginYAML(t *testing.T, dir, fileName, content string) { t.Helper() -- Gitee