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

yuluo-yx 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 66d7d954ca [ISSUE #7590] Make supportSwaggerPluginSet a volatile 
instance field. (#7604)
66d7d954ca is described below

commit 66d7d954ca37d651a5ad916f988a8081157a7ab4
Author: poisongodv <[email protected]>
AuthorDate: Fri Oct 16 23:28:40 2026 +0800

    [ISSUE #7590] Make supportSwaggerPluginSet a volatile instance field. 
(#7604)
---
 .../manager/impl/LoadServiceDocEntryImpl.java      |  9 +++++---
 .../manager/impl/LoadServiceDocEntryImplTest.java  | 27 ++++++++++++++++++++++
 2 files changed, 33 insertions(+), 3 deletions(-)

diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImpl.java
index ce17099203..6e51df09b1 100755
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImpl.java
@@ -62,8 +62,11 @@ import static 
org.apache.shenyu.common.constant.Constants.SYS_DEFAULT_NAMESPACE_
 public class LoadServiceDocEntryImpl implements LoadServiceDocEntry {
     private static final Logger LOG = 
LoggerFactory.getLogger(LoadServiceDocEntryImpl.class);
 
-    @SuppressWarnings("unchecked")
-    private static Set<String> supportSwaggerPluginSet = 
Collections.emptySet();
+    /**
+     * Written by {@link #loadApiDocument()} and read from discovery sync 
callbacks on other threads,
+     * so it must be volatile to be safely published.
+     */
+    private volatile Set<String> supportSwaggerPluginSet = 
Collections.emptySet();
 
     private final SelectorService selectorService;
 
@@ -182,7 +185,7 @@ public class LoadServiceDocEntryImpl implements 
LoadServiceDocEntry {
         if (CollectionUtils.isEmpty(pluginDOList)) {
             return Collections.emptyList();
         }
-        supportSwaggerPluginSet = new HashSet<>(pluginNames);
+        supportSwaggerPluginSet = Collections.unmodifiableSet(new 
HashSet<>(pluginNames));
         List<String> pluginIds = 
pluginDOList.stream().map(PluginDO::getId).collect(Collectors.toList());
         CommonPager<SelectorVO> commonPager = selectorService.listByPage(new 
SelectorQuery(pluginIds, null, new PageParameter(1, Integer.MAX_VALUE), 
SYS_DEFAULT_NAMESPACE_ID));
         List<SelectorVO> clusterList = commonPager.getDataList();
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImplTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImplTest.java
index a88bfd83fc..477254d90b 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImplTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImplTest.java
@@ -47,9 +47,12 @@ import java.util.Date;
 import java.util.List;
 import java.util.Set;
 import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
 
 import static 
org.apache.shenyu.common.constant.Constants.SYS_DEFAULT_NAMESPACE_ID;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.verify;
 
@@ -148,4 +151,28 @@ public class LoadServiceDocEntryImplTest {
         loadServiceDocEntry.loadDocOnUpstreamChanged(changedList, eventType);
         verify(pullSwaggerDocService).pullApiDocument((Set<UpstreamInstance>) 
any());
     }
+
+    @Test
+    public void testLoadDocOnUpstreamChangedFromAnotherThread() throws 
Exception {
+        this.testLoadApiDocument();
+        DiscoveryUpstreamData discoveryUpstreamData = new 
DiscoveryUpstreamData();
+        discoveryUpstreamData.setUrl("127.0.0.1:8080");
+        DiscoverySyncData supported = new DiscoverySyncData();
+        supported.setPluginName("divide");
+        supported.setSelectorName("test");
+        
supported.setUpstreamDataList(Collections.singletonList(discoveryUpstreamData));
+        DiscoverySyncData unsupported = new DiscoverySyncData();
+        unsupported.setPluginName("dubbo");
+        unsupported.setSelectorName("test");
+        
unsupported.setUpstreamDataList(Collections.singletonList(discoveryUpstreamData));
+
+        // discovery sync callbacks run on a different thread from the one 
that loaded the supported plugins
+        CompletableFuture.runAsync(() -> {
+            
loadServiceDocEntry.loadDocOnUpstreamChanged(Collections.singletonList(unsupported),
 DataEventTypeEnum.CREATE);
+            
loadServiceDocEntry.loadDocOnUpstreamChanged(Collections.singletonList(supported),
 DataEventTypeEnum.CREATE);
+        }).get(10, TimeUnit.SECONDS);
+
+        // once by testLoadApiDocument, once for the supported plugin, never 
for the unsupported one
+        verify(pullSwaggerDocService, 
times(2)).pullApiDocument((Set<UpstreamInstance>) any());
+    }
 }

Reply via email to