This is an automated email from the ASF dual-hosted git repository. liuhongyu pushed a commit to branch fix/fix_upstream_check in repository https://gitbox.apache.org/repos/asf/shenyu.git
commit 099c0cbbd5024711ce532a2198ff264732c87d10 Author: liuhy <[email protected]> AuthorDate: Tue Feb 10 08:52:29 2026 +0800 fix: improve upstream cache management and add recovery test for empty events --- .../loadbalancer/cache/UpstreamCacheManager.java | 7 ++-- .../shenyu/loadbalancer/entity/Upstream.java | 2 +- .../cache/UpstreamCacheManagerTest.java | 38 ++++++++++++++++++++++ .../shenyu/loadbalancer/entity/UpstreamTest.java | 8 +++++ 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManager.java b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManager.java index 2c13303970..246eace594 100644 --- a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManager.java +++ b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManager.java @@ -150,8 +150,11 @@ public final class UpstreamCacheManager { // Check if the list is empty first to avoid unnecessary processing if (actualUpstreamList.isEmpty()) { - List<Upstream> existUpstreamList = MapUtils.computeIfAbsent(UPSTREAM_MAP, selectorId, k -> Lists.newArrayList()); - removeAllUpstreams(selectorId, existUpstreamList); + List<Upstream> existUpstreamList = UPSTREAM_MAP.get(selectorId); + if (Objects.nonNull(existUpstreamList)) { + removeAllUpstreams(selectorId, existUpstreamList); + } + UPSTREAM_MAP.remove(selectorId); return; } diff --git a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/Upstream.java b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/Upstream.java index 36656e3493..d832dc28ff 100644 --- a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/Upstream.java +++ b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/Upstream.java @@ -509,7 +509,7 @@ public final class Upstream { @Override public int hashCode() { - return Objects.hash(protocol, url, weight); + return Objects.hash(protocol, url); } @Override diff --git a/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManagerTest.java b/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManagerTest.java index 17b449df3c..53290d867b 100644 --- a/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManagerTest.java +++ b/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManagerTest.java @@ -278,6 +278,44 @@ public class UpstreamCacheManagerTest { upstreamCacheManager.removeByKey(testSelectorId); } + @Test + @Order(10) + public void testSubmitCanRecoverAfterEmptyUpstreamEvent() { + final UpstreamCacheManager upstreamCacheManager = UpstreamCacheManager.getInstance(); + final String testSelectorId = "RECOVER_AFTER_EMPTY_EVENT_TEST"; + + List<Upstream> initialList = new ArrayList<>(1); + initialList.add(Upstream.builder() + .protocol("http://") + .url("recover-upstream:8080") + .status(true) + .healthCheckEnabled(false) + .build()); + upstreamCacheManager.submit(testSelectorId, initialList); + List<Upstream> firstSubmitResult = upstreamCacheManager.findUpstreamListBySelectorId(testSelectorId); + Assertions.assertNotNull(firstSubmitResult); + Assertions.assertFalse(firstSubmitResult.isEmpty()); + + upstreamCacheManager.submit(testSelectorId, new ArrayList<>()); + List<Upstream> afterEmptySubmitResult = upstreamCacheManager.findUpstreamListBySelectorId(testSelectorId); + Assertions.assertTrue(Objects.isNull(afterEmptySubmitResult) || afterEmptySubmitResult.isEmpty()); + + List<Upstream> recoveredList = new ArrayList<>(1); + recoveredList.add(Upstream.builder() + .protocol("http://") + .url("recover-upstream:8080") + .status(true) + .healthCheckEnabled(false) + .build()); + upstreamCacheManager.submit(testSelectorId, recoveredList); + List<Upstream> secondSubmitResult = upstreamCacheManager.findUpstreamListBySelectorId(testSelectorId); + Assertions.assertNotNull(secondSubmitResult); + Assertions.assertFalse(secondSubmitResult.isEmpty()); + Assertions.assertTrue(secondSubmitResult.stream().anyMatch(upstream -> "recover-upstream:8080".equals(upstream.getUrl()))); + + upstreamCacheManager.removeByKey(testSelectorId); + } + /** * Helper method to get the UpstreamCheckTask using reflection. */ diff --git a/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/entity/UpstreamTest.java b/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/entity/UpstreamTest.java index 9a9146f6b0..ab7d009707 100644 --- a/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/entity/UpstreamTest.java +++ b/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/entity/UpstreamTest.java @@ -73,7 +73,15 @@ public class UpstreamTest { .weight(1) .status(true) .build(); + Upstream upstream4 = Upstream.builder() + .protocol("https://") + .url("url") + .weight(2) + .status(true) + .build(); Assertions.assertEquals(upstream2, upstream3); + Assertions.assertEquals(upstream2, upstream4); + Assertions.assertEquals(upstream2.hashCode(), upstream4.hashCode()); Assertions.assertNotNull(upstream2.toString()); Assertions.assertTrue(upstream2.hashCode() >= 0); }
