[BUG] Etcd selectInstances leaks watchers that cannot be unwatched
- 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-registry
### What happened
`EtcdInstanceRegisterRepository.selectInstances()` creates an etcd watcher the first time a service key is selected, but it does not keep the returned `Watch.Watcher` handle:
```java
this.client.watchKeyChanges(watchKey, Watch.listener(response -> {
...
watcherInstanceRegisterMap.put(selectKey, getInstanceRegisterFun.apply(serverNodes));
}));
```
In the same class, explicit `watchInstances()` stores watcher handles in `watchCache`:
```java
final Watch.Watcher watcher = this.client.watchKeyChanges(watchKey, Watch.listener(...));
watchCache.put(watchKey, watcher);
```
`unWatchInstances()` and `close()` only close watchers present in `watchCache`:
```java
if (watchCache.containsKey(key)) {
watchCache.get(key).forEach(Watch.Watcher::close);
watchCache.removeAll(key);
}
watchCache.values().forEach(Watch.Watcher::close);
watchCache.clear();
```
Because the watcher created by `selectInstances()` is not stored, it cannot be closed by `unWatchInstances()` or `close()`. Repeated service selections can leave background etcd watchers active for the lifetime of the client.
### What you expected to happen
Every watcher created by `EtcdInstanceRegisterRepository` should be tracked and closed. The watcher from `selectInstances()` should either be stored in `watchCache` under a consistent key, or `selectInstances()` should avoid creating a persistent watcher that the repository cannot later release.
### How to reproduce
1. Configure Etcd discovery.
2. Call `EtcdInstanceRegisterRepository.selectInstances(serviceName)` for a service key that is not already in `watcherInstanceRegisterMap`.
3. The method creates a watcher for `InstancePathConstants.buildInstanceParentPath(serviceName)`.
4. Call `unWatchInstances(...)` or `close()`.
5. Only watchers in `watchCache` are closed, so the watcher created from `selectInstances()` remains untracked.
### Debug logs
_No response_
### Environment
Current master branch.
### Are you willing to submit PR?
- [ ] Yes I am willing to submit a PR!
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in EtcdInstanceRegisterRepository at selectInstances(), then compare its watcher creation with watchInstances(), unWatchInstances(), and close(). Ensure the watcher created during selection is accounted for by the repository lifecycle, and verify that selecting a service followed by unWatchInstances() or close() leaves no active watcher.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- distributed-systems
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100