dubbo.apache.org/dubbo-go/v3@v3.1.1/remoting/etcdv3/listener.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package etcdv3
    19  
    20  import (
    21  	"sync"
    22  	"time"
    23  )
    24  
    25  import (
    26  	gxetcd "github.com/dubbogo/gost/database/kv/etcd/v3"
    27  	"github.com/dubbogo/gost/log/logger"
    28  
    29  	perrors "github.com/pkg/errors"
    30  
    31  	"go.etcd.io/etcd/api/v3/mvccpb"
    32  
    33  	clientv3 "go.etcd.io/etcd/client/v3"
    34  )
    35  
    36  import (
    37  	"dubbo.apache.org/dubbo-go/v3/remoting"
    38  )
    39  
    40  // nolint
    41  type EventListener struct {
    42  	client     *gxetcd.Client
    43  	keyMapLock sync.RWMutex
    44  	keyMap     map[string]struct{}
    45  	wg         sync.WaitGroup
    46  }
    47  
    48  // NewEventListener returns a EventListener instance
    49  func NewEventListener(client *gxetcd.Client) *EventListener {
    50  	return &EventListener{
    51  		client: client,
    52  		keyMap: make(map[string]struct{}),
    53  	}
    54  }
    55  
    56  // ListenServiceNodeEvent Listen on a spec key.It will return true when spec key deleted,
    57  // and return false when deep layer connection lose
    58  func (l *EventListener) ListenServiceNodeEvent(key string, listener ...remoting.DataListener) bool {
    59  	defer l.wg.Done()
    60  	for {
    61  		wc, err := l.client.Watch(key)
    62  		if err != nil {
    63  			logger.Warnf("WatchExist{key:%s} = error{%v}", key, err)
    64  			return false
    65  		}
    66  
    67  		select {
    68  
    69  		// client stopped
    70  		case <-l.client.Done():
    71  			logger.Warnf("etcd client stopped")
    72  			return false
    73  
    74  		// client ctx stop
    75  		case <-l.client.GetCtx().Done():
    76  			logger.Warnf("etcd client ctx cancel")
    77  			return false
    78  
    79  		// handle etcd events
    80  		case e, ok := <-wc:
    81  			if !ok {
    82  				logger.Warnf("etcd watch-chan closed")
    83  				return false
    84  			}
    85  
    86  			if e.Err() != nil {
    87  				logger.Errorf("etcd watch ERR {err: %s}", e.Err())
    88  				continue
    89  			}
    90  			for _, event := range e.Events {
    91  				if l.handleEvents(event, listener...) {
    92  					// if event is delete
    93  					return true
    94  				}
    95  			}
    96  		}
    97  	}
    98  }
    99  
   100  // return true means the event type is DELETE
   101  // return false means the event type is CREATE || UPDATE
   102  func (l *EventListener) handleEvents(event *clientv3.Event, listeners ...remoting.DataListener) bool {
   103  	logger.Infof("got a etcd event {type: %s, key: %s}", event.Type, event.Kv.Key)
   104  
   105  	switch event.Type {
   106  	// the etcdv3 event just include PUT && DELETE
   107  	case mvccpb.PUT:
   108  		for _, listener := range listeners {
   109  			switch event.IsCreate() {
   110  			case true:
   111  				logger.Infof("etcd get event (key{%s}) = event{EventNodeDataCreated}", event.Kv.Key)
   112  				listener.DataChange(remoting.Event{
   113  					Path:    string(event.Kv.Key),
   114  					Action:  remoting.EventTypeAdd,
   115  					Content: string(event.Kv.Value),
   116  				})
   117  			case false:
   118  				logger.Infof("etcd get event (key{%s}) = event{EventNodeDataChanged}", event.Kv.Key)
   119  				listener.DataChange(remoting.Event{
   120  					Path:    string(event.Kv.Key),
   121  					Action:  remoting.EventTypeUpdate,
   122  					Content: string(event.Kv.Value),
   123  				})
   124  			}
   125  		}
   126  		return false
   127  	case mvccpb.DELETE:
   128  		logger.Warnf("etcd get event (key{%s}) = event{EventNodeDeleted}", event.Kv.Key)
   129  		return true
   130  
   131  	default:
   132  		return false
   133  	}
   134  }
   135  
   136  // ListenServiceNodeEventWithPrefix listens on a set of key with spec prefix
   137  func (l *EventListener) ListenServiceNodeEventWithPrefix(prefix string, listener ...remoting.DataListener) {
   138  	defer l.wg.Done()
   139  	for {
   140  		wc, err := l.client.WatchWithPrefix(prefix)
   141  		if err != nil {
   142  			logger.Warnf("listenDirEvent(key{%s}) = error{%v}", prefix, err)
   143  		}
   144  
   145  		select {
   146  
   147  		// client stopped
   148  		case <-l.client.Done():
   149  			logger.Warnf("etcd client stopped")
   150  			return
   151  
   152  		// client ctx stop
   153  		case <-l.client.GetCtx().Done():
   154  			logger.Warnf("etcd client ctx cancel")
   155  			return
   156  
   157  		// etcd event stream
   158  		case e, ok := <-wc:
   159  
   160  			if !ok {
   161  				logger.Warnf("etcd watch-chan closed")
   162  				return
   163  			}
   164  
   165  			if e.Err() != nil {
   166  				logger.Errorf("etcd watch ERR {err: %s}", e.Err())
   167  				continue
   168  			}
   169  			for _, event := range e.Events {
   170  				l.handleEvents(event, listener...)
   171  			}
   172  		}
   173  	}
   174  }
   175  
   176  func timeSecondDuration(sec int) time.Duration {
   177  	return time.Duration(sec) * time.Second
   178  }
   179  
   180  // ListenServiceEvent is invoked by etcdv3 ConsumerRegistry::Registe/ etcdv3 ConsumerRegistry::get/etcdv3 ConsumerRegistry::getListener
   181  // registry.go:Listen -> listenServiceEvent -> listenDirEvent -> listenServiceNodeEvent
   182  // registry.go:Listen -> listenServiceEvent -> listenServiceNodeEvent
   183  func (l *EventListener) ListenServiceEvent(key string, listener remoting.DataListener) {
   184  	l.keyMapLock.RLock()
   185  	_, ok := l.keyMap[key]
   186  	l.keyMapLock.RUnlock()
   187  	if ok {
   188  		logger.Warnf("etcdv3 key %s has already been listened.", key)
   189  		return
   190  	}
   191  
   192  	l.keyMapLock.Lock()
   193  	l.keyMap[key] = struct{}{}
   194  	l.keyMapLock.Unlock()
   195  
   196  	keyList, valueList, err := l.client.GetChildren(key)
   197  	if err != nil {
   198  		logger.Warnf("Get new node path {%v} 's content error,message is  {%v}", key, perrors.WithMessage(err, "get children"))
   199  	}
   200  
   201  	logger.Debugf("get key children list %s, keys %v values %v", key, keyList, valueList)
   202  
   203  	for i, k := range keyList {
   204  		logger.Infof("got children list key -> %s", k)
   205  		listener.DataChange(remoting.Event{
   206  			Path:    k,
   207  			Action:  remoting.EventTypeAdd,
   208  			Content: valueList[i],
   209  		})
   210  	}
   211  
   212  	logger.Debugf("[ETCD Listener] listen dubbo provider key{%s} event and wait to get all provider etcdv3 nodes", key)
   213  	l.wg.Add(1)
   214  	go func(key string, listener remoting.DataListener) {
   215  		l.ListenServiceNodeEventWithPrefix(key, listener)
   216  		logger.Warnf("listenDirEvent(key{%s}) goroutine exit now", key)
   217  	}(key, listener)
   218  
   219  	logger.Infof("[ETCD Listener] listen dubbo service key{%s}", key)
   220  	l.wg.Add(1)
   221  	go func(key string) {
   222  		if l.ListenServiceNodeEvent(key) {
   223  			listener.DataChange(remoting.Event{Path: key, Action: remoting.EventTypeDel})
   224  		}
   225  		logger.Warnf("listenSelf(etcd key{%s}) goroutine exit now", key)
   226  	}(key)
   227  }
   228  
   229  // nolint
   230  func (l *EventListener) Close() {
   231  	l.wg.Wait()
   232  }