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