apache / apache/shenyu

[BUG] RPC client registration does not persist upstream status changes in selector handles

Open
#6,522 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
8.8k
Forks
3.1k
Avg merge
7d 1h
Merged PRs (30d)
85

Description

### Search before asking

- [x] I had searched in the [issues](https://github.com/apache/shenyu/issues) and found no similar issues.

### Apache ShenYu Component

shenyu-admin

### What happened

The Dubbo, gRPC, and Tars client registration services detect upstream status changes, but they do not apply those changes to the `existList` that is serialized back into the selector handle.

For example, `ShenyuClientRegisterGrpcServiceImpl.buildHandle(...)` does this:

```java
List existList = GsonUtils.getInstance().fromCurrentList(selectorDO.getHandle(), GrpcUpstream.class);
...
List diffStatusList = addList.stream().filter(upstream -> !upstream.isStatus()
|| existList.stream().anyMatch(e -> e.equals(upstream) && e.isStatus() != upstream.isStatus())).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(diffStatusList)) {
canAddList.addAll(diffStatusList);
}
...
return GsonUtils.getInstance().toJson(CollectionUtils.isEmpty(existList) ? canAddList : existList);
```

The same pattern exists in the Dubbo and Tars registration services.

The upstream `equals(...)` methods compare identity fields such as host/protocol/url/namespace, but they do not include `status`. Therefore a status-only change is detected in `diffStatusList`, but the matching object already in `existList` keeps its old status. Since the method serializes `existList` when it is not empty, the selector handle written back to DB still contains the stale status.

This affects status changes such as a single-node deleted/offline event where the new upstream is marked `status=false` before diffing.

### Expected behavior

When an existing upstream is re-registered with a different status, the matching item inside `existList` should be updated before the handle is serialized. The persisted selector handle should reflect the same status change that the registration flow detected.

### How to reproduce

1. Register a Dubbo, gRPC, or Tars upstream so the selector handle contains the upstream with `status=true`.
2. Send a registration event for the same upstream with `EventType.DELETED`, causing the newly built upstream to be marked `status=false`.
3. `diffStatusList` detects the changed status and adds it to `canAddList`.
4. Because `existList` is not updated, the method returns `GsonUtils.toJson(existList)` with the original `status=true` value.
5. The DB selector handle remains stale, so admin display/export/restart replay can use the old upstream status.

### Debug logs

_No response_

### Environment

Current `master` branch.

### Are you willing to submit a PR?

- [ ] Yes I am willing to submit a PR!

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with ShenyuClientRegisterGrpcServiceImpl.buildHandle(...) and trace the corresponding Dubbo and Tars registration-service implementations, focusing on how existList is compared and serialized. Reproduce a status-only re-registration for an existing upstream, then verify that the persisted selector handle reflects the changed status for all three protocols.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.