fix: improve upstream cache management and add recovery test for empty events#6294
fix: improve upstream cache management and add recovery test for empty events#6294
Conversation
There was a problem hiding this comment.
Pull request overview
This PR improves upstream cache behavior when an empty upstream event is submitted, and aligns Upstream.hashCode() with the existing equals() semantics to prevent inconsistent collection behavior.
Changes:
- Fix
Upstream.hashCode()to hash only(protocol, url)to matchequals(). - Update
UpstreamCacheManager.submit()empty-list handling to avoid leaving stale entries inUPSTREAM_MAP. - Add/extend unit tests to cover recovery after an empty upstream submit and verify updated equality/hash behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/Upstream.java |
Makes hashCode() consistent with equals() by removing weight from hashing. |
shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManager.java |
Changes empty-upstream submission handling to remove selector entries from UPSTREAM_MAP. |
shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/entity/UpstreamTest.java |
Expands tests to validate equality/hashCode consistency across different weights. |
shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManagerTest.java |
Adds a recovery test ensuring submit works after an empty upstream event. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| List<Upstream> existUpstreamList = UPSTREAM_MAP.get(selectorId); | ||
| if (Objects.nonNull(existUpstreamList)) { | ||
| removeAllUpstreams(selectorId, existUpstreamList); | ||
| } | ||
| UPSTREAM_MAP.remove(selectorId); |
There was a problem hiding this comment.
When upstreamList is empty, this branch removes upstreams based on UPSTREAM_MAP, but UPSTREAM_MAP is populated from task.getHealthyUpstreamListBySelectorId(...) (i.e., only healthy upstreams). Any entries that only exist in the task's unhealthyUpstream map will not be cleared, so a selector can retain stale unhealthy state after an empty event. Consider clearing the task state directly (e.g., task.triggerRemoveAll(selectorId)) in addition to (or instead of) iterating over existUpstreamList, and then remove the selectorId from UPSTREAM_MAP.
| List<Upstream> existUpstreamList = UPSTREAM_MAP.get(selectorId); | |
| if (Objects.nonNull(existUpstreamList)) { | |
| removeAllUpstreams(selectorId, existUpstreamList); | |
| } | |
| UPSTREAM_MAP.remove(selectorId); | |
| // Clear both cached upstreams and all health-check state for this selector. | |
| removeByKey(selectorId); |
Make sure that:
./mvnw clean install -Dmaven.javadoc.skip=true.