diff --git a/kenaito-conf-go-client/client.go b/kenaito-conf-go-client/client.go index 1067a4c..b25aabc 100644 --- a/kenaito-conf-go-client/client.go +++ b/kenaito-conf-go-client/client.go @@ -223,6 +223,18 @@ func (c *Client) fetchChanged() error { delete(wrapper.Data, "latest.fetch.timestamp") } + // 处理删除的配置 + if deletedKeysStr, ok := wrapper.Data["deletedKeys"]; ok && deletedKeysStr != "" { + deletedKeys := strings.Split(deletedKeysStr, ",") + c.mu.Lock() + for _, key := range deletedKeys { + delete(c.configs, key) + } + c.mu.Unlock() + log.Printf("[ConfigClient] %d configs deleted", len(deletedKeys)) + delete(wrapper.Data, "deletedKeys") + } + if len(wrapper.Data) > 0 { changed := make(map[string]string) for k, v := range wrapper.Data { diff --git a/kenaito-conf-nodejs-client/lib/client.js b/kenaito-conf-nodejs-client/lib/client.js index 257f2f4..0b5849c 100644 --- a/kenaito-conf-nodejs-client/lib/client.js +++ b/kenaito-conf-nodejs-client/lib/client.js @@ -127,6 +127,17 @@ export class ConfigClient { } delete changedData['latest.fetch.timestamp']; + // 处理删除的配置 + const deletedKeysStr = changedData['deletedKeys']; + if (deletedKeysStr) { + const deletedKeys = deletedKeysStr.split(','); + for (const key of deletedKeys) { + delete this.configs[key]; + } + console.info('[ConfigClient]', deletedKeys.length, 'configs deleted'); + delete changedData['deletedKeys']; + } + const changed = {}; for (const [k, v] of Object.entries(changedData)) { changed[k] = v; diff --git a/kenaito-conf-python-client/kenaito_conf/client.py b/kenaito-conf-python-client/kenaito_conf/client.py index 11920c3..ca4ed60 100644 --- a/kenaito-conf-python-client/kenaito_conf/client.py +++ b/kenaito-conf-python-client/kenaito_conf/client.py @@ -103,6 +103,15 @@ class ConfigClient: if ts: self._last_time = int(ts) + # 处理删除的配置 + deleted_keys_str = changed_data.pop("deletedKeys", None) + if deleted_keys_str: + deleted_keys = deleted_keys_str.split(",") + with self._lock: + for key in deleted_keys: + self._configs.pop(key, None) + logger.info("[ConfigClient] %d configs deleted", len(deleted_keys)) + if changed_data: changed = {} for k, v in changed_data.items(): diff --git a/kenaito-conf-springboot2-client/src/main/java/cn/odboy/confcenter/ConfigcenterContext.java b/kenaito-conf-springboot2-client/src/main/java/cn/odboy/confcenter/ConfigcenterContext.java index 03821e9..6b395c5 100644 --- a/kenaito-conf-springboot2-client/src/main/java/cn/odboy/confcenter/ConfigcenterContext.java +++ b/kenaito-conf-springboot2-client/src/main/java/cn/odboy/confcenter/ConfigcenterContext.java @@ -415,6 +415,42 @@ public class ConfigcenterContext { } } + public synchronized void removeConfigs(List keys) { + for (String key : keys) { + localProps.remove(key); + logger.info("Config [{}] removed", key); + } + // Update Spring Environment property source + if (applicationContext != null) { + StandardEnvironment environment = (StandardEnvironment) applicationContext.getEnvironment(); + MutablePropertySources propertySources = environment.getPropertySources(); + synchronized (propertySources) { + if (propertySources.contains(MANAGER_PROPERTY_SOURCE)) { + Properties properties = new Properties(); + Object source = propertySources.get(MANAGER_PROPERTY_SOURCE); + if (source instanceof MapPropertySource) { + Map map = ((MapPropertySource) source).getSource(); + for (Entry entry : map.entrySet()) { + if (!keys.contains(entry.getKey())) { + properties.put(entry.getKey(), entry.getValue()); + } + } + } else if (source instanceof PropertiesPropertySource) { + Map src = ((PropertiesPropertySource) source).getSource(); + for (Entry entry : src.entrySet()) { + if (!keys.contains(entry.getKey())) { + properties.put(entry.getKey(), entry.getValue().toString()); + } + } + } + propertySources.replace(MANAGER_PROPERTY_SOURCE, new PropertiesPropertySource(MANAGER_PROPERTY_SOURCE, properties)); + } + } + } + // Refresh @Value and @ConfigurationProperties fields + refreshDynamicConfigFields(); + } + private void refreshDynamicConfigFields() { if (applicationContext != null) { try { diff --git a/kenaito-conf-springboot2-client/src/main/java/cn/odboy/confcenter/InternalConfigChangeListener.java b/kenaito-conf-springboot2-client/src/main/java/cn/odboy/confcenter/InternalConfigChangeListener.java index e6c8a46..590fcec 100644 --- a/kenaito-conf-springboot2-client/src/main/java/cn/odboy/confcenter/InternalConfigChangeListener.java +++ b/kenaito-conf-springboot2-client/src/main/java/cn/odboy/confcenter/InternalConfigChangeListener.java @@ -63,6 +63,15 @@ public class InternalConfigChangeListener { if (data.containsKey(LATEST_FETCH_TIMESTAMP)) { params.put("lastTime", Long.parseLong(data.remove(LATEST_FETCH_TIMESTAMP).toString())); } + // 处理删除的配置 + if (data.containsKey("deletedKeys")) { + String deletedKeysStr = (String) data.remove("deletedKeys"); + if (deletedKeysStr != null && !deletedKeysStr.isEmpty()) { + String[] deletedKeys = deletedKeysStr.split(","); + context.removeConfigs(java.util.Arrays.asList(deletedKeys)); + logger.info("[ConfigClient] {} configs deleted", deletedKeys.length); + } + } if (!data.isEmpty()) context.updateConfig(data); } } diff --git a/server/internal/handler/config_api.go b/server/internal/handler/config_api.go index 07c9642..0bf7849 100644 --- a/server/internal/handler/config_api.go +++ b/server/internal/handler/config_api.go @@ -9,6 +9,7 @@ import ( "net" "net/http" "strconv" + "strings" "time" "github.com/gin-gonic/gin" @@ -172,6 +173,32 @@ func (h *ConfigApiHandler) FetchChangedConfigs(c *gin.Context) { result := make(map[string]string) var configIds []int + // 查询已删除的配置(enabled=0 且 updated_at > lastTime),返回 deletedKeys + var deletedKeys []string + if !req.IgnoreGlobal && app.GroupId != nil { + var deletedGlobalConfigs []model.AppConfig + dao.Engine.Where("env = ? AND version = ? AND enabled = 0 AND group_id = ? AND (app_id is null OR app_id = 0) AND updated_at > ?", + req.Env, version, *app.GroupId, lastUpdateTime).Find(&deletedGlobalConfigs) + for _, cfg := range deletedGlobalConfigs { + kvMap := h.parseService.ParseConfigToKVMap(&cfg) + for k := range kvMap { + deletedKeys = append(deletedKeys, k) + } + } + } + var deletedAppConfigs []model.AppConfig + dao.Engine.Where("env = ? AND version = ? AND enabled = 0 AND app_id = ? AND updated_at > ?", + req.Env, version, app.Id, lastUpdateTime).Find(&deletedAppConfigs) + for _, cfg := range deletedAppConfigs { + kvMap := h.parseService.ParseConfigToKVMap(&cfg) + for k := range kvMap { + deletedKeys = append(deletedKeys, k) + } + } + if len(deletedKeys) > 0 { + result["deletedKeys"] = strings.Join(deletedKeys, ",") + } + // load global changed configs if !req.IgnoreGlobal && app.GroupId != nil { var globalConfigs []model.AppConfig