diff --git a/internal/plugin/manager.go b/internal/plugin/manager.go index fecc8c31e0a44c07f60dc35d1ea15b3fe53700db..f8d2d0f4ea554e6518fb59375eb78a71449a0839 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 53fa0105b4aafb23200ca87600936d51f5759205..d184e9d124cab69ffa572045280fc1b238852f10 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()