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 4f47abc734 fix: use thread-safe upstream lists in UpstreamCheckService
(#6704) (#7053)
4f47abc734 is described below
commit 4f47abc7341aba297b027fd7a4aa92aa27b18421
Author: Southern <[email protected]>
AuthorDate: Wed Sep 30 09:56:33 2026 +0800
fix: use thread-safe upstream lists in UpstreamCheckService (#6704) (#7053)
* fix: use thread-safe upstream lists in UpstreamCheckService (#6704)
Build upstream data with CopyOnWriteArrayList so submit and scheduled
health checks can safely modify and iterate the same selector entries.
Ensure replacement and health-check result lists stored in UPSTREAM_MAP
use the same thread-safe implementation, and add regression assertions
for lists loaded by fetchUpstreamData.
* fix: preserve thread-safe upstream list references (#6704)
Reuse existing CopyOnWriteArrayList instances when updating UPSTREAM_MAP
and only copy lists that are not thread-safe. This preserves the shared
list reference used by asynchronous submit tasks while ensuring ordinary
lists are converted before being stored.
---------
Co-authored-by: zhengpeng <[email protected]>
Co-authored-by: aias00 <[email protected]>
---
.../shenyu/admin/service/impl/UpstreamCheckService.java | 11 +++++++----
.../apache/shenyu/admin/service/UpstreamCheckServiceTest.java | 2 ++
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/UpstreamCheckService.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/UpstreamCheckService.java
index 3a6ef7d9ab..d060915590 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/UpstreamCheckService.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/UpstreamCheckService.java
@@ -61,7 +61,6 @@ import org.springframework.stereotype.Component;
import jakarta.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -282,7 +281,7 @@ public class UpstreamCheckService {
if (!REGISTER_TYPE_HTTP.equalsIgnoreCase(registerType)) {
return;
}
- UPSTREAM_MAP.put(selectorId, commonUpstreams);
+ UPSTREAM_MAP.put(selectorId, toThreadSafeList(commonUpstreams));
}
private void scheduled() {
@@ -398,7 +397,7 @@ public class UpstreamCheckService {
}
removePendingSync(successList);
if (!successList.isEmpty()) {
- UPSTREAM_MAP.put(selectorId, successList);
+ UPSTREAM_MAP.put(selectorId, toThreadSafeList(successList));
updateSelectorHandler(selectorId, successList);
} else {
UPSTREAM_MAP.remove(selectorId);
@@ -411,6 +410,10 @@ public class UpstreamCheckService {
successList.forEach(commonUpstream ->
PENDING_SYNC.remove(commonUpstream.hashCode()));
}
+ private List<CommonUpstream> toThreadSafeList(final List<CommonUpstream>
upstreams) {
+ return upstreams instanceof CopyOnWriteArrayList ? upstreams : new
CopyOnWriteArrayList<>(upstreams);
+ }
+
private void updateSelectorHandler(final String selectorId, final
List<CommonUpstream> aliveList) {
SelectorDO selectorDO = selectorMapper.selectById(selectorId);
if (Objects.isNull(selectorDO)) {
@@ -481,7 +484,7 @@ public class UpstreamCheckService {
.filter(Objects::nonNull)
.forEach(selectorDO -> {
String name = pluginMap.get(selectorDO.getPluginId());
- List<CommonUpstream> commonUpstreams = new LinkedList<>();
+ List<CommonUpstream> commonUpstreams = new
CopyOnWriteArrayList<>();
discoveryUpstreamService.findBySelectorId(selectorDO.getId()).stream()
.map(DiscoveryTransfer.INSTANCE::mapToCommonUpstream)
.forEach(commonUpstreams::add);
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/UpstreamCheckServiceTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/UpstreamCheckServiceTest.java
index 2c91eddd12..cfa650183a 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/UpstreamCheckServiceTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/UpstreamCheckServiceTest.java
@@ -259,8 +259,10 @@ public final class UpstreamCheckServiceTest {
upstreamCheckService.fetchUpstreamData();
assertTrue(upstreamMap.containsKey(MOCK_SELECTOR_NAME));
assertEquals(2, upstreamMap.get(MOCK_SELECTOR_NAME).size());
+ assertTrue(upstreamMap.get(MOCK_SELECTOR_NAME) instanceof
CopyOnWriteArrayList);
assertTrue(upstreamMap.containsKey(MOCK_SELECTOR_NAME_OTHER));
assertEquals(2, upstreamMap.get(MOCK_SELECTOR_NAME_OTHER).size());
+ assertTrue(upstreamMap.get(MOCK_SELECTOR_NAME_OTHER) instanceof
CopyOnWriteArrayList);
}
@Test