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 }