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());
+ }
}