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 &registry.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  }