This is an automated email from the ASF dual-hosted git repository.

dmsolr pushed a commit to branch fix/refresh-stale-config-guard-6874
in repository https://gitbox.apache.org/repos/asf/shenyu.git

commit bf89fa194483989e86a3da1c697a5df9b0a4ea3e
Author: Luke Haochao Zhuang <[email protected]>
AuthorDate: Mon Aug 31 15:40:59 2026 +0800

    fix: remove faulty size guard so REFRESH cleans up stale plugin/auth/meta 
config nodes (#6874)
    
    The REFRESH/MYSELF branch of 
AbstractNodeDataChangedListener#onCommonChanged only removed stale entries when 
the old set strictly outnumbered the new one, so refreshes with equal or larger 
cardinality (e.g. old=[A,B,C,D] -> new=[C,D,E,F]) left orphaned config nodes in 
nacos/apollo/polaris. Removed the size guard and fixed the stale-entry 
delConfig call to use the correct namespaced key.
---
 .../listener/AbstractNodeDataChangedListener.java  |  4 ++--
 .../AbstractNodeDataChangedListenerTest.java       | 25 ++++++++++++++++++++++
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git 
a/shenyu-admin-listener/shenyu-admin-listener-api/src/main/java/org/apache/shenyu/admin/listener/AbstractNodeDataChangedListener.java
 
b/shenyu-admin-listener/shenyu-admin-listener-api/src/main/java/org/apache/shenyu/admin/listener/AbstractNodeDataChangedListener.java
index 21e6b6d594..5b1fc6741c 100644
--- 
a/shenyu-admin-listener/shenyu-admin-listener-api/src/main/java/org/apache/shenyu/admin/listener/AbstractNodeDataChangedListener.java
+++ 
b/shenyu-admin-listener/shenyu-admin-listener-api/src/main/java/org/apache/shenyu/admin/listener/AbstractNodeDataChangedListener.java
@@ -131,9 +131,9 @@ public abstract class AbstractNodeDataChangedListener 
implements DataChangedList
                     final List<String> configDataNames = 
this.getConfigDataNames(configKeyPrefix);
                     changedList.forEach(changedData -> 
publishConfig(configKeyPrefix + mapperToKey.apply(changedData), changedData));
 
-                    if (Objects.nonNull(configDataNames) && 
configDataNames.size() > changedList.size()) {
+                    if (Objects.nonNull(configDataNames)) {
                         configDataNames.removeAll(changeNames);
-                        configDataNames.forEach(this::delConfig);
+                        configDataNames.forEach(staleName -> 
delConfig(configKeyPrefix + staleName));
                     }
 
                     publishConfig(configKeyPrefix + 
DefaultNodeConstants.LIST_STR, changeNames);
diff --git 
a/shenyu-admin-listener/shenyu-admin-listener-api/src/test/java/org/apache/shenyu/admin/listener/AbstractNodeDataChangedListenerTest.java
 
b/shenyu-admin-listener/shenyu-admin-listener-api/src/test/java/org/apache/shenyu/admin/listener/AbstractNodeDataChangedListenerTest.java
index f552617407..a1a9cbeff9 100644
--- 
a/shenyu-admin-listener/shenyu-admin-listener-api/src/test/java/org/apache/shenyu/admin/listener/AbstractNodeDataChangedListenerTest.java
+++ 
b/shenyu-admin-listener/shenyu-admin-listener-api/src/test/java/org/apache/shenyu/admin/listener/AbstractNodeDataChangedListenerTest.java
@@ -18,6 +18,7 @@
 package org.apache.shenyu.admin.listener;
 
 import org.apache.shenyu.common.constant.DefaultNodeConstants;
+import org.apache.shenyu.common.dto.PluginData;
 import org.apache.shenyu.common.dto.SelectorData;
 import org.apache.shenyu.common.enums.DataEventTypeEnum;
 import org.apache.shenyu.common.utils.GsonUtils;
@@ -69,6 +70,30 @@ public final class AbstractNodeDataChangedListenerTest {
         assertTrue(listener.wasDeleted(selectorDataKey(SECOND_PLUGIN, 
STALE_ID)));
     }
 
+    @Test
+    public void 
testOnPluginChangedRefreshWithEqualCardinalityRemovesStaleEntries() {
+        TestNodeDataChangedListener listener = new 
TestNodeDataChangedListener();
+        final String configKeyPrefix = NAMESPACE_ID + 
DefaultNodeConstants.JOIN_POINT + "plugin" + DefaultNodeConstants.JOIN_POINT;
+        listener.putConfig(configKeyPrefix + DefaultNodeConstants.LIST_STR, 
Arrays.asList("A", "B", "C", "D"));
+        listener.putConfig(configKeyPrefix + "A", pluginData("A"));
+        listener.putConfig(configKeyPrefix + "B", pluginData("B"));
+
+        listener.onPluginChanged(Arrays.asList(
+                pluginData("C"), pluginData("D"), pluginData("E"), 
pluginData("F")), DataEventTypeEnum.REFRESH);
+
+        assertNull(listener.config(configKeyPrefix + "A"));
+        assertNull(listener.config(configKeyPrefix + "B"));
+        assertTrue(listener.wasDeleted(configKeyPrefix + "A"));
+        assertTrue(listener.wasDeleted(configKeyPrefix + "B"));
+    }
+
+    private static PluginData pluginData(final String name) {
+        return PluginData.builder()
+                .namespaceId(NAMESPACE_ID)
+                .name(name)
+                .build();
+    }
+
     private static SelectorData selectorData(final String pluginName, final 
String selectorId) {
         return SelectorData.builder()
                 .namespaceId(NAMESPACE_ID)

Reply via email to