github.com/micro/go-micro/v2@v2.9.1/registry/etcd/watcher.go (about) 1 package etcd 2 3 import ( 4 "context" 5 "errors" 6 "time" 7 8 "github.com/coreos/etcd/clientv3" 9 "github.com/micro/go-micro/v2/registry" 10 ) 11 12 type etcdWatcher struct { 13 stop chan bool 14 w clientv3.WatchChan 15 client *clientv3.Client 16 timeout time.Duration 17 } 18 19 func newEtcdWatcher(r *etcdRegistry, timeout time.Duration, opts ...registry.WatchOption) (registry.Watcher, error) { 20 var wo registry.WatchOptions 21 for _, o := range opts { 22 o(&wo) 23 } 24 25 ctx, cancel := context.WithCancel(context.Background()) 26 stop := make(chan bool, 1) 27 28 go func() { 29 <-stop 30 cancel() 31 }() 32 33 watchPath := prefix 34 if len(wo.Service) > 0 { 35 watchPath = servicePath(wo.Service) + "/" 36 } 37 38 return &etcdWatcher{ 39 stop: stop, 40 w: r.client.Watch(ctx, watchPath, clientv3.WithPrefix(), clientv3.WithPrevKV()), 41 client: r.client, 42 timeout: timeout, 43 }, nil 44 } 45 46 func (ew *etcdWatcher) Next() (*registry.Result, error) { 47 for wresp := range ew.w { 48 if wresp.Err() != nil { 49 return nil, wresp.Err() 50 } 51 if wresp.Canceled { 52 return nil, errors.New("could not get next") 53 } 54 for _, ev := range wresp.Events { 55 service := decode(ev.Kv.Value) 56 var action string 57 58 switch ev.Type { 59 case clientv3.EventTypePut: 60 if ev.IsCreate() { 61 action = "create" 62 } else if ev.IsModify() { 63 action = "update" 64 } 65 case clientv3.EventTypeDelete: 66 action = "delete" 67 68 // get service from prevKv 69 service = decode(ev.PrevKv.Value) 70 } 71 72 if service == nil { 73 continue 74 } 75 return ®istry.Result{ 76 Action: action, 77 Service: service, 78 }, nil 79 } 80 } 81 return nil, errors.New("could not get next") 82 } 83 84 func (ew *etcdWatcher) Stop() { 85 select { 86 case <-ew.stop: 87 return 88 default: 89 close(ew.stop) 90 } 91 }