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

Reply via email to