dubbo.apache.org/dubbo-go/v3@v3.1.1/registry/polaris/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 polaris 19 20 import ( 21 "fmt" 22 "strconv" 23 "sync" 24 "time" 25 ) 26 27 import ( 28 "github.com/dubbogo/gost/log/logger" 29 30 perrors "github.com/pkg/errors" 31 32 api "github.com/polarismesh/polaris-go" 33 "github.com/polarismesh/polaris-go/pkg/model" 34 ) 35 36 import ( 37 "dubbo.apache.org/dubbo-go/v3/common" 38 "dubbo.apache.org/dubbo-go/v3/common/constant" 39 "dubbo.apache.org/dubbo-go/v3/common/extension" 40 "dubbo.apache.org/dubbo-go/v3/registry" 41 "dubbo.apache.org/dubbo-go/v3/remoting" 42 "dubbo.apache.org/dubbo-go/v3/remoting/polaris" 43 ) 44 45 const ( 46 RegistryConnDelay = 3 47 defaultHeartbeatIntervalSec = 5 48 ) 49 50 func init() { 51 extension.SetRegistry(constant.PolarisKey, newPolarisRegistry) 52 } 53 54 // newPolarisRegistry will create new instance 55 func newPolarisRegistry(url *common.URL) (registry.Registry, error) { 56 if err := polaris.InitSDKContext(url); err != nil { 57 return &polarisRegistry{}, err 58 } 59 60 providerApi, err := polaris.GetProviderAPI() 61 if err != nil { 62 return nil, err 63 } 64 65 consumerApi, err := polaris.GetConsumerAPI() 66 if err != nil { 67 return nil, err 68 } 69 70 pRegistry := &polarisRegistry{ 71 url: url, 72 namespace: url.GetParam(constant.RegistryNamespaceKey, constant.PolarisDefaultNamespace), 73 provider: providerApi, 74 consumer: consumerApi, 75 registryUrls: make([]*common.URL, 0, 4), 76 watchers: map[string]*PolarisServiceWatcher{}, 77 } 78 79 return pRegistry, nil 80 } 81 82 type polarisRegistry struct { 83 namespace string 84 url *common.URL 85 consumer api.ConsumerAPI 86 provider api.ProviderAPI 87 lock sync.RWMutex 88 registryUrls []*common.URL 89 listenerLock sync.RWMutex 90 watchers map[string]*PolarisServiceWatcher 91 } 92 93 // Register will register the service @url to its polaris registry center. 94 func (pr *polarisRegistry) Register(url *common.URL) error { 95 if getCategory(url) != "providers" { 96 return nil 97 } 98 99 serviceName := url.Interface() 100 request := createRegisterParam(url, serviceName) 101 request.Namespace = pr.namespace 102 resp, err := pr.provider.RegisterInstance(request) 103 if err != nil { 104 return err 105 } 106 107 if resp.Existed { 108 logger.Warnf("instance already regist, namespace:%+v, service:%+v, host:%+v, port:%+v", 109 request.Namespace, request.Service, request.Host, request.Port) 110 } 111 url.SetParam(constant.PolarisInstanceID, resp.InstanceID) 112 113 pr.lock.Lock() 114 pr.registryUrls = append(pr.registryUrls, url) 115 pr.lock.Unlock() 116 117 return nil 118 } 119 120 // UnRegister returns nil if unregister successfully. If not, returns an error. 121 func (pr *polarisRegistry) UnRegister(url *common.URL) error { 122 request := createDeregisterParam(url, url.Interface()) 123 request.Namespace = pr.namespace 124 if err := pr.provider.Deregister(request); err != nil { 125 return perrors.WithMessagef(err, "fail to deregister(conf:%+v)", url) 126 } 127 return nil 128 } 129 130 // Subscribe returns nil if subscribing registry successfully. If not returns an error. 131 func (pr *polarisRegistry) Subscribe(url *common.URL, notifyListener registry.NotifyListener) error { 132 133 role, _ := strconv.Atoi(url.GetParam(constant.RegistryRoleKey, "")) 134 if role != common.CONSUMER { 135 return nil 136 } 137 timer := time.NewTimer(time.Duration(RegistryConnDelay) * time.Second) 138 defer timer.Stop() 139 140 for { 141 serviceName := url.Interface() 142 watcher, err := pr.createPolarisWatcher(serviceName) 143 if err != nil { 144 logger.Warnf("getwatcher() = err:%v", perrors.WithStack(err)) 145 <-timer.C 146 timer.Reset(time.Duration(RegistryConnDelay) * time.Second) 147 continue 148 } 149 150 listener, err := NewPolarisListener(watcher) 151 if err != nil { 152 logger.Warnf("getListener() = err:%v", perrors.WithStack(err)) 153 <-timer.C 154 timer.Reset(time.Duration(RegistryConnDelay) * time.Second) 155 continue 156 } 157 158 for { 159 serviceEvent, err := listener.Next() 160 161 if err != nil { 162 logger.Warnf("Selector.watch() = error{%v}", perrors.WithStack(err)) 163 listener.Close() 164 return err 165 } 166 logger.Infof("update begin, service event: %v", serviceEvent.String()) 167 notifyListener.Notify(serviceEvent) 168 } 169 } 170 } 171 172 // UnSubscribe returns nil if unsubscribing registry successfully. If not returns an error. 173 func (pr *polarisRegistry) UnSubscribe(url *common.URL, notifyListener registry.NotifyListener) error { 174 // TODO wait polaris support it 175 return perrors.New("UnSubscribe not support in polarisRegistry") 176 } 177 178 // LoadSubscribeInstances load subscribe instance 179 func (pr *polarisRegistry) LoadSubscribeInstances(url *common.URL, notify registry.NotifyListener) error { 180 serviceName := url.Interface() 181 resp, err := pr.consumer.GetInstances(&api.GetInstancesRequest{ 182 GetInstancesRequest: model.GetInstancesRequest{ 183 Service: serviceName, 184 Namespace: pr.namespace, 185 }, 186 }) 187 if err != nil { 188 return perrors.New(fmt.Sprintf("could not query the instances for serviceName=%s,namespace=%s,error=%v", 189 serviceName, pr.namespace, err)) 190 } 191 for i := range resp.Instances { 192 if newUrl := generateUrl(resp.Instances[i]); newUrl != nil { 193 notify.Notify(®istry.ServiceEvent{Action: remoting.EventTypeAdd, Service: newUrl}) 194 } 195 } 196 return nil 197 } 198 199 // GetURL returns polaris registry's url. 200 func (pr *polarisRegistry) GetURL() *common.URL { 201 return pr.url 202 } 203 204 func (pr *polarisRegistry) createPolarisWatcher(serviceName string) (*PolarisServiceWatcher, error) { 205 206 pr.listenerLock.Lock() 207 defer pr.listenerLock.Unlock() 208 209 if _, exist := pr.watchers[serviceName]; !exist { 210 subscribeParam := &api.WatchServiceRequest{ 211 WatchServiceRequest: model.WatchServiceRequest{ 212 Key: model.ServiceKey{ 213 Namespace: pr.namespace, 214 Service: serviceName, 215 }, 216 }, 217 } 218 219 watcher, err := newPolarisWatcher(subscribeParam, pr.consumer) 220 if err != nil { 221 return nil, err 222 } 223 pr.watchers[serviceName] = watcher 224 } 225 226 return pr.watchers[serviceName], nil 227 } 228 229 // Destroy stop polaris registry. 230 func (pr *polarisRegistry) Destroy() { 231 for i := range pr.registryUrls { 232 url := pr.registryUrls[i] 233 err := pr.UnRegister(url) 234 logger.Infof("DeRegister Polaris URL:%+v", url) 235 if err != nil { 236 logger.Errorf("Deregister Polaris URL:%+v err:%v", url, err.Error()) 237 } 238 } 239 return 240 } 241 242 // IsAvailable always return true when use polaris 243 func (pr *polarisRegistry) IsAvailable() bool { 244 return true 245 } 246 247 // createRegisterParam convert dubbo url to polaris instance register request 248 func createRegisterParam(url *common.URL, serviceName string) *api.InstanceRegisterRequest { 249 common.HandleRegisterIPAndPort(url) 250 port, _ := strconv.Atoi(url.Port) 251 252 metadata := make(map[string]string, len(url.GetParams())) 253 url.RangeParams(func(key, value string) bool { 254 metadata[key] = value 255 return true 256 }) 257 metadata[constant.PolarisDubboPath] = url.Path 258 259 ver := url.GetParam("version", "") 260 261 req := &api.InstanceRegisterRequest{ 262 InstanceRegisterRequest: model.InstanceRegisterRequest{ 263 Service: serviceName, 264 Host: url.Ip, 265 Port: port, 266 Protocol: &url.Protocol, 267 Version: &ver, 268 Metadata: metadata, 269 }, 270 } 271 272 req.SetTTL(defaultHeartbeatIntervalSec) 273 274 return req 275 } 276 277 // createDeregisterParam convert dubbo url to polaris instance deregister request 278 func createDeregisterParam(url *common.URL, serviceName string) *api.InstanceDeRegisterRequest { 279 common.HandleRegisterIPAndPort(url) 280 port, _ := strconv.Atoi(url.Port) 281 return &api.InstanceDeRegisterRequest{ 282 InstanceDeRegisterRequest: model.InstanceDeRegisterRequest{ 283 Service: serviceName, 284 Host: url.Ip, 285 Port: port, 286 }, 287 } 288 }