一、micro的registry/etcdv3接收到删除事件时在独立使用时没发送事件
issues: https://github.com/micro/go-plugins/issues/108
原因
go-plugins/registry/etcdv3在单独使用时如果接收到删除事件,会因为没有从cache从取到service 信息而不发送通知,导致watch的地方没有收到通知
func (ew *etcdv3Watcher) Next() (*registry.Result, error) {
for wresp := range ew.w {
if wresp.Err() != nil {
return nil, wresp.Err()
}
for _, ev := range wresp.Events {
service := decode(ev.Kv.Value)
var action string
switch ev.Type {
case clientv3.EventTypePut:
if ev.IsCreate() {
action = "create"
} else if ev.IsModify() {
action = "update"
}
case clientv3.EventTypeDelete:
action = "delete"
// get the cached value
ctx, cancel := context.WithTimeout(context.Background(), ew.timeout)
defer cancel()
resp, err := ew.client.Get(ctx, path.Join(cachePrefix, string(ev.Kv.Key)))
if err != nil {
return nil, err
}
for _, ev := range resp.Kvs {
service = decode(ev.Value)
}
}
if service == nil {
continue
}
return ®istry.Result{
Action: action,
Service: service,
}, nil
}
}
return nil, errors.New("could not get next")
}
@TODO
- 从ev.Kv.Value里取数据decode到service不成功?
- ev.Kv.Value是不是删除时的值如果是,应该decode成功才对
实例证明:删除时ev.Kv.Value取到的值为空
解决办法
watch的时候添加clientv3.WithPrevKV()参数,可以取到上一次的KV
return &etcdv3Watcher{
stop: stop,
w: r.client.Watch(ctx, prefix, clientv3.WithPrefix(), clientv3.WithPrevKV()),
client: r.client,
timeout: timeout,
}, nil
二、如果没有注册服务就watch会报:not found
解决判断
去掉GetService方法里的判断,删除以下代码
if len(rsp.Kvs) == 0 {
return nil, registry.ErrNotFound
}