dubbo.apache.org/dubbo-go/v3@v3.1.1/registry/etcdv3/registry.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  	"fmt"
    22  	"path"
    23  	"strings"
    24  	"sync"
    25  )
    26  
    27  import (
    28  	gxetcd "github.com/dubbogo/gost/database/kv/etcd/v3"
    29  	"github.com/dubbogo/gost/log/logger"
    30  
    31  	perrors "github.com/pkg/errors"
    32  )
    33  
    34  import (
    35  	"dubbo.apache.org/dubbo-go/v3/common"
    36  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    37  	"dubbo.apache.org/dubbo-go/v3/common/extension"
    38  	"dubbo.apache.org/dubbo-go/v3/registry"
    39  	"dubbo.apache.org/dubbo-go/v3/remoting/etcdv3"
    40  )
    41  
    42  const (
    43  	Name = "etcdv3"
    44  )
    45  
    46  func init() {
    47  	extension.SetRegistry(Name, newETCDV3Registry)
    48  }
    49  
    50  type etcdV3Registry struct {
    51  	registry.BaseRegistry
    52  	cltLock        sync.Mutex
    53  	client         *gxetcd.Client
    54  	listenerLock   sync.RWMutex
    55  	listener       *etcdv3.EventListener
    56  	dataListener   *dataListener
    57  	configListener *configurationListener
    58  }
    59  
    60  // Client gets the etcdv3 client
    61  func (r *etcdV3Registry) Client() *gxetcd.Client {
    62  	return r.client
    63  }
    64  
    65  // SetClient sets the etcdv3 client
    66  func (r *etcdV3Registry) SetClient(client *gxetcd.Client) {
    67  	r.client = client
    68  }
    69  
    70  // ClientLock returns lock for client
    71  func (r *etcdV3Registry) ClientLock() *sync.Mutex {
    72  	return &r.cltLock
    73  }
    74  
    75  func newETCDV3Registry(url *common.URL) (registry.Registry, error) {
    76  	timeout := url.GetParamDuration(constant.RegistryTimeoutKey, constant.DefaultRegTimeout)
    77  
    78  	logger.Infof("etcd address is: %v, timeout is: %s", url.Location, timeout.String())
    79  
    80  	r := &etcdV3Registry{}
    81  
    82  	r.InitBaseRegistry(url, r)
    83  
    84  	if err := etcdv3.ValidateClient(
    85  		r,
    86  		gxetcd.WithName(gxetcd.RegistryETCDV3Client),
    87  		gxetcd.WithTimeout(timeout),
    88  		gxetcd.WithEndpoints(strings.Split(url.Location, ",")...),
    89  	); err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	r.handleClientRestart()
    94  	r.InitListeners()
    95  
    96  	return r, nil
    97  }
    98  
    99  // InitListeners init listeners of etcd registry center
   100  func (r *etcdV3Registry) InitListeners() {
   101  	r.listener = etcdv3.NewEventListener(r.client)
   102  	r.configListener = NewConfigurationListener(r)
   103  	r.dataListener = NewRegistryDataListener(r.configListener)
   104  }
   105  
   106  // DoRegister actually do the register job in the registry center of etcd
   107  // for lease
   108  func (r *etcdV3Registry) DoRegister(root string, node string) error {
   109  	return r.client.RegisterTemp(path.Join(root, node), "")
   110  }
   111  
   112  // nolint
   113  func (r *etcdV3Registry) DoUnregister(root string, node string) error {
   114  	return perrors.New("DoUnregister is not support in etcdV3Registry")
   115  }
   116  
   117  // CloseAndNilClient closes listeners and clear client
   118  func (r *etcdV3Registry) CloseAndNilClient() {
   119  	r.client.Close()
   120  	r.client = nil
   121  }
   122  
   123  // CloseListener closes listeners
   124  func (r *etcdV3Registry) CloseListener() {
   125  	if r.configListener != nil {
   126  		r.configListener.Close()
   127  	}
   128  }
   129  
   130  // CreatePath create the path in the registry center of etcd
   131  func (r *etcdV3Registry) CreatePath(k string) error {
   132  	var tmpPath string
   133  	for _, str := range strings.Split(k, "/")[1:] {
   134  		tmpPath = path.Join(tmpPath, "/", str)
   135  		if err := r.client.Put(tmpPath, ""); err != nil {
   136  			return perrors.WithMessagef(err, "create path %s in etcd", tmpPath)
   137  		}
   138  	}
   139  
   140  	return nil
   141  }
   142  
   143  // DoSubscribe actually subscribe the provider URL
   144  func (r *etcdV3Registry) DoSubscribe(svc *common.URL) (registry.Listener, error) {
   145  	r.listenerLock.RLock()
   146  	configListener := r.configListener
   147  	r.listenerLock.RUnlock()
   148  	if r.listener == nil {
   149  		r.cltLock.Lock()
   150  		client := r.client
   151  		r.cltLock.Unlock()
   152  		if client == nil {
   153  			return nil, perrors.New("etcd client broken")
   154  		}
   155  		r.listenerLock.Lock()
   156  		r.listener = etcdv3.NewEventListener(r.client) // new client & listener
   157  		r.listenerLock.Unlock()
   158  	}
   159  
   160  	// register the svc to dataListener
   161  	r.dataListener.AddInterestedURL(svc)
   162  	go r.listener.ListenServiceEvent(fmt.Sprintf("/dubbo/%s/"+constant.DefaultCategory, svc.Service()), r.dataListener)
   163  
   164  	return configListener, nil
   165  }
   166  
   167  func (r *etcdV3Registry) DoUnsubscribe(conf *common.URL) (registry.Listener, error) {
   168  	return nil, perrors.New("DoUnsubscribe is not support in etcdV3Registry")
   169  }
   170  
   171  // LoadSubscribeInstances load subscribe instance
   172  func (r *etcdV3Registry) LoadSubscribeInstances(_ *common.URL, _ registry.NotifyListener) error {
   173  	return nil
   174  }
   175  
   176  func (r *etcdV3Registry) handleClientRestart() {
   177  	r.WaitGroup().Add(1)
   178  	go etcdv3.HandleClientRestart(r)
   179  }