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

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 60e9445f51 fix(sofa): detect selector upstream changes against the 
last seen config (#7282)
60e9445f51 is described below

commit 60e9445f5128748ed241b92d27aaf32660f9f032
Author: Sean-Walker0 <[email protected]>
AuthorDate: Sat Sep 26 12:14:08 2026 +0800

    fix(sofa): detect selector upstream changes against the last seen config 
(#7282)
---
 .../plugin/sofa/handler/SofaPluginDataHandler.java | 22 +++++-
 .../sofa/handler/SofaPluginDataHandlerTest.java    | 78 +++++++++++++++++++++-
 2 files changed, 96 insertions(+), 4 deletions(-)

diff --git 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-sofa/src/main/java/org/apache/shenyu/plugin/sofa/handler/SofaPluginDataHandler.java
 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-sofa/src/main/java/org/apache/shenyu/plugin/sofa/handler/SofaPluginDataHandler.java
index 9268046162..0c823a8e3e 100644
--- 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-sofa/src/main/java/org/apache/shenyu/plugin/sofa/handler/SofaPluginDataHandler.java
+++ 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-sofa/src/main/java/org/apache/shenyu/plugin/sofa/handler/SofaPluginDataHandler.java
@@ -27,6 +27,9 @@ import 
org.apache.shenyu.plugin.base.handler.PluginDataHandler;
 import org.apache.shenyu.common.utils.Singleton;
 import org.apache.shenyu.plugin.sofa.cache.ApplicationConfigCache;
 
+import com.google.common.collect.Maps;
+
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -34,6 +37,14 @@ import java.util.Objects;
  */
 public class SofaPluginDataHandler implements PluginDataHandler {
 
+    /**
+     * Last seen sofa upstream config per selector id. The reference cache's
+     * upstream map is keyed by the full reference cache key (selector id,
+     * metadata path, protocol and registry hash), so the last-seen config is
+     * tracked here to detect whether a selector update really changed it.
+     */
+    private static final Map<String, SofaUpstream> SELECTOR_UPSTREAM_MAP = 
Maps.newConcurrentMap();
+
     @Override
     public void handlerPlugin(final PluginData pluginData) {
         if (Objects.nonNull(pluginData) && pluginData.getEnabled()) {
@@ -54,19 +65,26 @@ public class SofaPluginDataHandler implements 
PluginDataHandler {
     @Override
     public void handlerSelector(final SelectorData selectorData) {
         SofaUpstream nCacheUpstreams = 
GsonUtils.getInstance().fromJson(selectorData.getHandle(), SofaUpstream.class);
-        SofaUpstream oCacheUpstream = 
ApplicationConfigCache.getInstance().getUpstream(selectorData.getId());
+        SofaUpstream oCacheUpstream = 
SELECTOR_UPSTREAM_MAP.get(selectorData.getId());
         if (!Objects.equals(nCacheUpstreams, oCacheUpstream)) {
             
ApplicationConfigCache.getInstance().invalidateWithSelectorId(selectorData.getId());
+            if (Objects.isNull(nCacheUpstreams)) {
+                SELECTOR_UPSTREAM_MAP.remove(selectorData.getId());
+            } else {
+                SELECTOR_UPSTREAM_MAP.put(selectorData.getId(), 
nCacheUpstreams);
+            }
         }
     }
 
     @Override
     public void removePlugin(final PluginData pluginData) {
+        SELECTOR_UPSTREAM_MAP.clear();
         ApplicationConfigCache.getInstance().invalidateAll();
     }
-    
+
     @Override
     public void removeSelector(final SelectorData selectorData) {
+        SELECTOR_UPSTREAM_MAP.remove(selectorData.getId());
         
ApplicationConfigCache.getInstance().invalidateWithSelectorId(selectorData.getId());
     }
 
diff --git 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-sofa/src/test/java/org/apache/shenyu/plugin/sofa/handler/SofaPluginDataHandlerTest.java
 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-sofa/src/test/java/org/apache/shenyu/plugin/sofa/handler/SofaPluginDataHandlerTest.java
index 17b9a96473..dc1fbfa02a 100644
--- 
a/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-sofa/src/test/java/org/apache/shenyu/plugin/sofa/handler/SofaPluginDataHandlerTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-rpc/shenyu-plugin-sofa/src/test/java/org/apache/shenyu/plugin/sofa/handler/SofaPluginDataHandlerTest.java
@@ -17,10 +17,16 @@
 
 package org.apache.shenyu.plugin.sofa.handler;
 
+import com.alipay.sofa.rpc.config.ConsumerConfig;
+import com.google.common.cache.LoadingCache;
 import org.apache.shenyu.common.dto.PluginData;
+import org.apache.shenyu.common.dto.SelectorData;
 import org.apache.shenyu.common.dto.convert.plugin.SofaRegisterConfig;
+import org.apache.shenyu.common.dto.convert.selector.SofaUpstream;
 import org.apache.shenyu.common.enums.PluginEnum;
+import org.apache.shenyu.common.utils.GsonUtils;
 import org.apache.shenyu.common.utils.Singleton;
+import org.apache.shenyu.plugin.sofa.cache.ApplicationConfigCache;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.MethodOrderer;
 import org.junit.jupiter.api.Test;
@@ -28,8 +34,12 @@ import org.junit.jupiter.api.TestMethodOrder;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.junit.jupiter.MockitoExtension;
 
+import java.lang.reflect.Field;
+
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * SofaPluginDataHandlerTest.
@@ -37,14 +47,15 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 @ExtendWith(MockitoExtension.class)
 @TestMethodOrder(MethodOrderer.Alphanumeric.class)
 public final class SofaPluginDataHandlerTest {
-    
+
     private final String registryConfig = 
"{\"protocol\":\"zookeeper\",\"register\":\"127.0.0.1:2181\"}";
-    
+
     private SofaPluginDataHandler sofaPluginDataHandler;
 
     @BeforeEach
     public void setUp() {
         sofaPluginDataHandler = new SofaPluginDataHandler();
+        ApplicationConfigCache.getInstance().invalidateAll();
     }
 
     @Test
@@ -65,4 +76,67 @@ public final class SofaPluginDataHandlerTest {
     public void testPluginNamed() {
         assertEquals(sofaPluginDataHandler.pluginNamed(), 
PluginEnum.SOFA.getName());
     }
+
+    @Test
+    public void testHandlerSelectorSkipsInvalidationWhenUpstreamUnchanged() 
throws Exception {
+        String selectorId = "1532088187335";
+        String handle = 
"{\"register\":\"zookeeper://127.0.0.1:2181\",\"protocol\":\"bolt\"}";
+        seedReference(selectorId, handle);
+
+        // first event: nothing recorded yet, invalidates (cache rebuilt 
lazily anyway)
+        sofaPluginDataHandler.handlerSelector(selector(selectorId, handle));
+        
assertFalse(referenceCache().asMap().containsKey(referenceKey(selectorId, 
handle)));
+
+        // re-seed and send the same handle again: must NOT invalidate a 
second time
+        seedReference(selectorId, handle);
+        sofaPluginDataHandler.handlerSelector(selector(selectorId, handle));
+        
assertTrue(referenceCache().asMap().containsKey(referenceKey(selectorId, 
handle)),
+                "an unchanged selector handle must not invalidate live 
references");
+    }
+
+    @Test
+    public void testHandlerSelectorInvalidatesWhenUpstreamChanged() throws 
Exception {
+        String selectorId = "1532088187336";
+        String oldHandle = 
"{\"register\":\"zookeeper://127.0.0.1:2181\",\"protocol\":\"bolt\"}";
+        sofaPluginDataHandler.handlerSelector(selector(selectorId, oldHandle));
+        seedReference(selectorId, oldHandle);
+
+        sofaPluginDataHandler.handlerSelector(selector(selectorId,
+                
"{\"register\":\"zookeeper://127.0.0.2:2181\",\"protocol\":\"bolt\"}"));
+        
assertFalse(referenceCache().asMap().containsKey(referenceKey(selectorId, 
oldHandle)),
+                "a changed selector handle must invalidate live references");
+    }
+
+    @Test
+    public void testHandlerSelectorInvalidatesWhenHandleRemoved() throws 
Exception {
+        String selectorId = "1532088187337";
+        String handle = 
"{\"register\":\"zookeeper://127.0.0.1:2181\",\"protocol\":\"bolt\"}";
+        sofaPluginDataHandler.handlerSelector(selector(selectorId, handle));
+        seedReference(selectorId, handle);
+
+        // removing the handle must invalidate references built from the old 
handle
+        sofaPluginDataHandler.handlerSelector(selector(selectorId, null));
+        
assertFalse(referenceCache().asMap().containsKey(referenceKey(selectorId, 
handle)),
+                "a removed selector handle must invalidate live references");
+    }
+
+    private void seedReference(final String selectorId, final String handle) 
throws Exception {
+        referenceCache().put(referenceKey(selectorId, handle), new 
ConsumerConfig<>());
+    }
+
+    private String referenceKey(final String selectorId, final String handle) {
+        SofaUpstream upstream = GsonUtils.getInstance().fromJson(handle, 
SofaUpstream.class);
+        return 
ApplicationConfigCache.getInstance().generateUpstreamCacheKey(selectorId, 
"/sofa/findAll", upstream);
+    }
+
+    private SelectorData selector(final String id, final String handle) {
+        return SelectorData.builder().id(id).handle(handle).build();
+    }
+
+    @SuppressWarnings("unchecked")
+    private LoadingCache<String, 
ConsumerConfig<com.alipay.sofa.rpc.api.GenericService>> referenceCache() throws 
Exception {
+        Field field = ApplicationConfigCache.class.getDeclaredField("cache");
+        field.setAccessible(true);
+        return (LoadingCache<String, 
ConsumerConfig<com.alipay.sofa.rpc.api.GenericService>>) 
field.get(ApplicationConfigCache.getInstance());
+    }
 }

Reply via email to