Skip to content

fix: handle discovery upstream DELETE events in path data sync (#6661) - #7060

Open
wy471x wants to merge 7 commits into
apache:masterfrom
wy471x:fix_discoveryUpstreamHandlerEvent-ignores-DELETE-events
Open

wy471x wants to merge 7 commits into
apache:masterfrom
wy471x:fix_discoveryUpstreamHandlerEvent-ignores-DELETE-events

Conversation

@wy471x

@wy471x wy471x commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Make sure that:

  • You have read the contribution guidelines.
  • You submit test cases (unit or integration tests) that back your changes.
  • Your local test passed ./mvnw clean install -Dmaven.javadoc.skip=true.

Summary

Fixes #6661.

Path-based sync services (etcd / zookeeper / consul, all extending AbstractPathDataSyncService) do receive delete notifications for discovery upstream nodes: EtcdSyncDataService.watchChildChange fires super.event(configNamespace, deletePath, null, registerPath, EventType.DELETE) (EtcdSyncDataService.java:88), and event() dispatches it to discoveryUpstreamHandlerEvent. But that handler only acted when the event was not a delete, so the DELETE was silently dropped and DiscoveryUpstreamDataSubscriber#unSubscribe was never called. Every other entity in the same class (plugin, selector, rule, app auth, meta data, proxy selector) already handles DELETE.

Changes:

  1. AbstractPathDataSyncService.discoveryUpstreamHandlerEvent (AbstractPathDataSyncService.java:132) — added the missing DELETE branch: parses pluginName and the last path segment with the same split("/") pattern used by proxyHandlerEvent, builds a DiscoverySyncData carrying them, and calls the new un-cache hook. The PUT path is unchanged.
  2. AbstractPathDataSyncService.unCacheDiscoveryUpstreamData (AbstractPathDataSyncService.java:290) — new protected hook delegating to discoveryUpstreamDataSubscribers.forEach(e -> e.unSubscribe(...)), mirroring the existing unCacheProxySelectorData / unCacheMetaData helpers and the node-based counterpart AbstractNodeDataSyncService.unCacheDiscoveryUpstreamData.

Note on the parsed path segment: the discovery-upstream path ends with the selector id, not the selector name — AbstractPathDataChangedListener.onDiscoveryUpstreamChanged builds it with buildDiscoveryUpstreamPath(data.getNamespaceId(), data.getPluginName(), data.getSelectorId()), and the node-based sync sets selectorId for the same reason. This PR therefore sets selectorId (the issue text suggested "selector name").

Test Cases:

  • AbstractPathDataSyncServiceTest#testDiscoveryUpstreamHandlerEvent (AbstractPathDataSyncServiceTest.java:93) — dispatches event(...) for /{ns}/shenyu/discoveryUpstream/divide/{selectorId}: PUT triggers onSubscribe, DELETE triggers unSubscribe, and the captured DiscoverySyncData carries pluginName=divide / selectorId=testSelectorId.

Verification

  • ./mvnw clean install -Dmaven.javadoc.skip=true on JDK 21: whole reactor passes, with the one pre-existing order-dependent test excluded (-Dtest='!DubboReconcilerTest' -DfailIfNoTests=false). org.apache.shenyu.k8s.DubboReconcilerTest shares the static IngressCache with WebSocketReconcilerTest / DivideIngressReconcilerTest (all use mockedNamespace/mockedIngress) and fails purely on test execution order: it passes in isolation and reproduces the same failure on unmodified master. shenyu-kubernetes-controller does not depend on shenyu-sync-data-api.
  • Touched module and its dependents: shenyu-sync-data-api, shenyu-sync-data-etcd, shenyu-sync-data-zookeeper, shenyu-sync-data-consul — all tests pass.
  • checkstyle:check — 0 violations.

Not covered here: the gateway-side CommonDiscoveryUpstreamDataSubscriber#unSubscribe is still a no-op (//ignore), so actually evicting the cached upstream list (UpstreamCacheManager.removeByKey(selectorId)) on deletion remains a separate change in the discovery plugin handlers.

@Aias00, could you please help review this PR? Thank you!

close #6661

@dengliming
dengliming requested a lite review from Copilot September 16, 2026 10:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The Zookeeper adapter still drops DELETE events when data is null, so they do not reach the new handler.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Fixes path-based discovery-upstream DELETE handling and adds regression coverage.

Changes:

  • Dispatches DELETE events to subscribers and parses selector IDs.
  • Adds PUT/DELETE handler tests.
File summaries
File Reviewed changes
shenyu-sync-data-center/shenyu-sync-data-api/src/test/java/org/apache/shenyu/sync/data/core/AbstractPathDataSyncServiceTest.java Tests discovery-upstream PUT and DELETE notifications.
shenyu-sync-data-center/shenyu-sync-data-api/src/main/java/org/apache/shenyu/sync/data/core/AbstractPathDataSyncService.java Adds DELETE handling and subscriber uncache delegation.
Review details

Suppressed comments (1)

shenyu-sync-data-center/shenyu-sync-data-api/src/main/java/org/apache/shenyu/sync/data/core/AbstractPathDataSyncService.java:143

  • This new branch only forwards the delete to DiscoveryUpstreamDataSubscriber, but the production CommonDiscoveryUpstreamDataSubscriber.unSubscribe implementation is still a no-op, so the normal gateway path performs no cache eviction and stale upstreams continue receiving traffic. Please include the downstream eviction (by selectorId) in this fix, or scope the PR/issue claim so it does not present #6661 as resolved.
            unCacheDiscoveryUpstreamData(discoverySyncData);
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

.ifPresent(e -> cacheDiscoveryUpstreamData(GsonUtils.getInstance().fromJson(updateData, DiscoverySyncData.class)));
String pluginName = pathInfoArray[pathInfoArray.length - 2];
String selectorId = pathInfoArray[pathInfoArray.length - 1];
if (EventType.DELETE.equals(eventType)) {

@Aias00 Aias00 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved as PMC (Aias00). Small, well-scoped fix with regression tests; green CI, mergeable. Reviewed the diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] discoveryUpstreamHandlerEvent ignores DELETE events (etcd path) — stale upstreams never removed

4 participants