⚠️ Verification
🎯 Solution Description
The etcdv3 registry had three critical gaps compared to the zookeeper registry:
-
DoUnregister was not implemented — always returned "DoUnregister is not support in etcdV3Registry".
The fix deletes the corresponding etcd key via client.Delete, guarded by a client.Valid() check.
-
DoUnsubscribe was not implemented — always returned an error.
The fix introduces a per-service listener architecture: dataListener now holds a
subscribed map[string]ConfigurationListener keyed by service key, replacing the old
single shared configurationListener. Each DoSubscribe call creates an independent
configurationListener for that service; DoUnsubscribe closes and removes it.
-
Subscriptions were silently lost after reconnect — InitListeners (called by RestartCallBack
on reconnect) replaced dataListener with an empty new instance, discarding all active
subscriptions. The fix stores subscribeURL *common.URL on each configurationListener and
adds a recovery loop in InitListeners that mirrors the zookeeper registry: close stale
listeners, create fresh ones, restart ListenServiceEvent goroutines for every recovered URL.
etcdv3 注册中心相比 zookeeper 注册中心存在三个关键缺口:
-
DoUnregister 未实现 — 始终返回 "DoUnregister is not support in etcdV3Registry"。
修复:通过 client.Delete 删除对应 etcd key,调用前做 client.Valid() 校验。
-
DoUnsubscribe 未实现 — 始终返回错误。
修复:引入 per-service listener 架构,dataListener 改为以 service key 为键的
subscribed map,取代原来全局共享的单个 configurationListener。每次 DoSubscribe
为该服务创建独立的 configurationListener;DoUnsubscribe 关闭并移除对应 listener。
-
断线重连后订阅静默丢失 — InitListeners(重连时由 RestartCallBack 触发)将
dataListener 替换为空实例,所有活跃订阅被丢弃。
修复:在 configurationListener 上存储 subscribeURL *common.URL,在 InitListeners
中加入与 zookeeper 注册中心对齐的恢复循环:关闭旧 listener,为每个已订阅 URL 创建新
listener,重新启动 ListenServiceEvent goroutine。
📋 Use Cases
-
Services that need to deregister from etcd on graceful shutdown.
-
Services that dynamically subscribe/unsubscribe to providers at runtime.
-
Long-running applications deployed in environments with unstable etcd connections (container
restarts, network partitions, etcd leader elections) that require seamless reconnect without
losing active subscriptions.
-
需要在优雅停机时从 etcd 注销的服务。
-
运行时动态订阅/取消订阅 provider 的服务。
-
部署在网络不稳定环境(容器重启、网络分区、etcd leader 选举)中、要求无感知重连且不丢失
订阅的长期运行应用。
⚖️ Complexity & Risks
-
Medium complexity. The per-service listener refactor touches the core subscribe/unsubscribe path.
-
DataChange now iterates all subscribed keys (instead of returning on first match), which is
a correctness improvement for wildcard/any-condition scenarios but changes the semantics slightly.
-
InitListeners holds the old dataListener mutex for the duration of recovery via defer,
which may briefly delay concurrent DataChange calls — same trade-off as zookeeper.
-
中等复杂度,per-service listener 重构影响核心订阅/取消订阅路径。
-
DataChange 改为遍历全部匹配 key(原先匹配即返回),对 wildcard/any-condition 场景是正确性
修复,但语义有轻微变化。
-
InitListeners 通过 defer 持有旧 dataListener mutex 直至恢复完成,大量订阅时可能短暂
阻塞并发 DataChange,与 zookeeper 注册中心权衡一致。
🔗 External Dependencies
None. Changes are confined to registry/etcdv3/listener.go and registry/etcdv3/registry.go,
using existing remoting/etcdv3 and common.URL APIs.
无外部依赖,改动限于 registry/etcdv3/listener.go 和 registry/etcdv3/registry.go,
使用已有的 remoting/etcdv3 和 common.URL API。
📘 Additional Context
Reference implementation for reconnect recovery: registry/zookeeper/registry.go — InitListeners (line 92-120).
重连恢复逻辑参考实现:registry/zookeeper/registry.go — InitListeners(第 92-120 行)。
如果觉得可以的话Assign me 然后我了解到我们目前需要将新注册中心迁移到dubbo-go-extension内作为插件使用 可以实现后进行迁移
🎯 Solution Description
The etcdv3 registry had three critical gaps compared to the zookeeper registry:
DoUnregister was not implemented — always returned
"DoUnregister is not support in etcdV3Registry".The fix deletes the corresponding etcd key via
client.Delete, guarded by aclient.Valid()check.DoUnsubscribe was not implemented — always returned an error.
The fix introduces a per-service listener architecture:
dataListenernow holds asubscribed map[string]ConfigurationListenerkeyed by service key, replacing the oldsingle shared
configurationListener. EachDoSubscribecall creates an independentconfigurationListenerfor that service;DoUnsubscribecloses and removes it.Subscriptions were silently lost after reconnect —
InitListeners(called byRestartCallBackon reconnect) replaced
dataListenerwith an empty new instance, discarding all activesubscriptions. The fix stores
subscribeURL *common.URLon eachconfigurationListenerandadds a recovery loop in
InitListenersthat mirrors the zookeeper registry: close stalelisteners, create fresh ones, restart
ListenServiceEventgoroutines for every recovered URL.etcdv3 注册中心相比 zookeeper 注册中心存在三个关键缺口:
DoUnregister 未实现 — 始终返回
"DoUnregister is not support in etcdV3Registry"。修复:通过
client.Delete删除对应 etcd key,调用前做client.Valid()校验。DoUnsubscribe 未实现 — 始终返回错误。
修复:引入 per-service listener 架构,
dataListener改为以 service key 为键的subscribed map,取代原来全局共享的单个configurationListener。每次DoSubscribe为该服务创建独立的
configurationListener;DoUnsubscribe关闭并移除对应 listener。断线重连后订阅静默丢失 —
InitListeners(重连时由RestartCallBack触发)将dataListener替换为空实例,所有活跃订阅被丢弃。修复:在
configurationListener上存储subscribeURL *common.URL,在InitListeners中加入与 zookeeper 注册中心对齐的恢复循环:关闭旧 listener,为每个已订阅 URL 创建新
listener,重新启动
ListenServiceEventgoroutine。📋 Use Cases
Services that need to deregister from etcd on graceful shutdown.
Services that dynamically subscribe/unsubscribe to providers at runtime.
Long-running applications deployed in environments with unstable etcd connections (container
restarts, network partitions, etcd leader elections) that require seamless reconnect without
losing active subscriptions.
需要在优雅停机时从 etcd 注销的服务。
运行时动态订阅/取消订阅 provider 的服务。
部署在网络不稳定环境(容器重启、网络分区、etcd leader 选举)中、要求无感知重连且不丢失
订阅的长期运行应用。
⚖️ Complexity & Risks
Medium complexity. The per-service listener refactor touches the core subscribe/unsubscribe path.
DataChangenow iterates all subscribed keys (instead of returning on first match), which isa correctness improvement for wildcard/any-condition scenarios but changes the semantics slightly.
InitListenersholds the olddataListenermutex for the duration of recovery viadefer,which may briefly delay concurrent
DataChangecalls — same trade-off as zookeeper.中等复杂度,per-service listener 重构影响核心订阅/取消订阅路径。
DataChange改为遍历全部匹配 key(原先匹配即返回),对 wildcard/any-condition 场景是正确性修复,但语义有轻微变化。
InitListeners通过defer持有旧dataListenermutex 直至恢复完成,大量订阅时可能短暂阻塞并发
DataChange,与 zookeeper 注册中心权衡一致。🔗 External Dependencies
None. Changes are confined to
registry/etcdv3/listener.goandregistry/etcdv3/registry.go,using existing
remoting/etcdv3andcommon.URLAPIs.无外部依赖,改动限于
registry/etcdv3/listener.go和registry/etcdv3/registry.go,使用已有的
remoting/etcdv3和common.URLAPI。📘 Additional Context
Reference implementation for reconnect recovery:
registry/zookeeper/registry.go—InitListeners(line 92-120).重连恢复逻辑参考实现:
registry/zookeeper/registry.go—InitListeners(第 92-120 行)。如果觉得可以的话Assign me 然后我了解到我们目前需要将新注册中心迁移到dubbo-go-extension内作为插件使用 可以实现后进行迁移