fix(management): reload plugins asynchronously after changes

This commit is contained in:
LTbinglingfeng
2026-06-17 01:06:57 +08:00
parent 13f51d96cb
commit a65ced4a92
4 changed files with 23 additions and 10 deletions
@@ -274,7 +274,7 @@ func (h *Handler) installPluginFromStore(c *gin.Context, goos, goarch string) {
reloadCfg := h.cfg
h.mu.Unlock()
h.reloadConfigAfterManagementSave(c.Request.Context(), reloadCfg)
h.reloadConfigAfterManagementSaveAsync(c.Request.Context(), reloadCfg)
log.WithFields(log.Fields{
"plugin_id": result.ID,
"source_id": source.ID,
@@ -511,12 +511,9 @@ func TestInstallPluginFromStoreOverwritesFilePreservesConfigAndReloads(t *testin
"https://downloads.example/checksums.txt": []byte(hex.EncodeToString(checksum[:]) + " " + archiveName + "\n"),
},
}
reloads := 0
reloads := make(chan *config.Config, 1)
h.SetConfigReloadHook(func(_ context.Context, cfg *config.Config) {
reloads++
if cfg != h.cfg {
t.Fatalf("reload config = %p, want handler config %p", cfg, h.cfg)
}
reloads <- cfg
})
rec := httptest.NewRecorder()
@@ -529,8 +526,8 @@ func TestInstallPluginFromStoreOverwritesFilePreservesConfigAndReloads(t *testin
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
}
if reloads != 1 {
t.Fatalf("reloads = %d, want 1", reloads)
if cfg := waitForAsyncReload(t, reloads); cfg != h.cfg {
t.Fatalf("reload config = %p, want handler config %p", cfg, h.cfg)
}
data, errRead := os.ReadFile(existingPath)
if errRead != nil {
+11 -2
View File
@@ -215,18 +215,27 @@ func (h *Handler) PatchPluginEnabled(c *gin.Context) {
}
h.mu.Lock()
defer h.mu.Unlock()
ensurePluginConfigMap(h.cfg)
item := h.cfg.Plugins.Configs[id]
node := pluginConfigNode(item)
setYAMLMappingValue(node, "enabled", boolYAMLNode(*body.Enabled))
updated, errConfig := pluginInstanceConfigFromNode(node)
if errConfig != nil {
h.mu.Unlock()
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid_config", "message": errConfig.Error()})
return
}
h.cfg.Plugins.Configs[id] = updated
h.persistLocked(c)
if errSave := config.SaveConfigPreserveComments(h.configFilePath, h.cfg); errSave != nil {
h.mu.Unlock()
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to save config: %v", errSave)})
return
}
reloadCfg := h.cfg
h.mu.Unlock()
h.reloadConfigAfterManagementSaveAsync(c.Request.Context(), reloadCfg)
c.JSON(http.StatusOK, gin.H{"status": "ok"})
}
// PutPluginConfig replaces plugins.configs.<id> with the request object.
@@ -241,6 +241,10 @@ func TestPatchPluginEnabledUpdatesOnlyPluginConfig(t *testing.T) {
},
configFilePath: writeTestConfigFile(t),
}
reloads := make(chan *config.Config, 1)
h.SetConfigReloadHook(func(_ context.Context, cfg *config.Config) {
reloads <- cfg
})
rec := httptest.NewRecorder()
c, _ := gin.CreateTestContext(rec)
@@ -253,6 +257,9 @@ func TestPatchPluginEnabledUpdatesOnlyPluginConfig(t *testing.T) {
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
}
if cfg := waitForAsyncReload(t, reloads); cfg != h.cfg {
t.Fatalf("reload config = %p, want handler config %p", cfg, h.cfg)
}
if h.cfg.Plugins.Enabled {
t.Fatal("global Plugins.Enabled changed to true")
}