dubbo.apache.org/dubbo-go/v3@v3.1.1/registry/directory/directory.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 directory 19 20 import ( 21 "fmt" 22 "net/url" 23 "os" 24 "sync" 25 "time" 26 ) 27 28 import ( 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/cluster/directory" 36 "dubbo.apache.org/dubbo-go/v3/cluster/directory/base" 37 "dubbo.apache.org/dubbo-go/v3/cluster/directory/static" 38 "dubbo.apache.org/dubbo-go/v3/cluster/router/chain" 39 "dubbo.apache.org/dubbo-go/v3/common" 40 "dubbo.apache.org/dubbo-go/v3/common/constant" 41 "dubbo.apache.org/dubbo-go/v3/common/extension" 42 "dubbo.apache.org/dubbo-go/v3/config" 43 "dubbo.apache.org/dubbo-go/v3/config_center" 44 _ "dubbo.apache.org/dubbo-go/v3/config_center/configurator" 45 "dubbo.apache.org/dubbo-go/v3/metrics" 46 metricsRegistry "dubbo.apache.org/dubbo-go/v3/metrics/registry" 47 "dubbo.apache.org/dubbo-go/v3/protocol" 48 "dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper" 49 "dubbo.apache.org/dubbo-go/v3/registry" 50 "dubbo.apache.org/dubbo-go/v3/remoting" 51 ) 52 53 func init() { 54 extension.SetDefaultRegistryDirectory(NewRegistryDirectory) 55 extension.SetDirectory(constant.RegistryProtocol, NewRegistryDirectory) 56 extension.SetDirectory(constant.ServiceRegistryProtocol, NewServiceDiscoveryRegistryDirectory) 57 } 58 59 // RegistryDirectory implementation of Directory: 60 // Invoker list returned from this Directory's list method have been filtered by Routers 61 type RegistryDirectory struct { 62 *base.Directory 63 cacheInvokers []protocol.Invoker 64 invokersLock sync.RWMutex 65 serviceType string 66 registry registry.Registry 67 cacheInvokersMap *sync.Map // use sync.map 68 consumerURL *common.URL 69 cacheOriginUrl *common.URL 70 configurators []config_center.Configurator 71 consumerConfigurationListener *consumerConfigurationListener 72 referenceConfigurationListener *referenceConfigurationListener 73 registerLock sync.Mutex // this lock if for register 74 SubscribedUrl *common.URL 75 RegisteredUrl *common.URL 76 } 77 78 // NewRegistryDirectory will create a new RegistryDirectory 79 func NewRegistryDirectory(url *common.URL, registry registry.Registry) (directory.Directory, error) { 80 if url.SubURL == nil { 81 return nil, perrors.Errorf("url is invalid, suburl can not be nil") 82 } 83 logger.Debugf("new RegistryDirectory for service :%s.", url.Key()) 84 dir := &RegistryDirectory{ 85 Directory: base.NewDirectory(url), 86 cacheInvokers: []protocol.Invoker{}, 87 cacheInvokersMap: &sync.Map{}, 88 serviceType: url.SubURL.Service(), 89 registry: registry, 90 } 91 92 dir.consumerURL = dir.getConsumerUrl(url.SubURL) 93 94 if routerChain, err := chain.NewRouterChain(); err == nil { 95 dir.Directory.SetRouterChain(routerChain) 96 } else { 97 logger.Warnf("fail to create router chain with url: %s, err is: %v", url.SubURL, err) 98 } 99 100 dir.consumerConfigurationListener = newConsumerConfigurationListener(dir) 101 dir.consumerConfigurationListener.addNotifyListener(dir) 102 dir.referenceConfigurationListener = newReferenceConfigurationListener(dir, url) 103 104 if err := dir.registry.LoadSubscribeInstances(url.SubURL, dir); err != nil { 105 return nil, err 106 } 107 metrics.Publish(metricsRegistry.NewDirectoryEvent(metricsRegistry.NumAllInc)) 108 return dir, nil 109 } 110 111 // subscribe from registry 112 func (dir *RegistryDirectory) Subscribe(url *common.URL) error { 113 logger.Infof("Start subscribing for service :%s with a new go routine.", url.Key()) 114 115 go func() { 116 dir.SubscribedUrl = url 117 if err := dir.registry.Subscribe(url, dir); err != nil { 118 logger.Error("registry.Subscribe(url:%v, dir:%v) = error:%v", url, dir, err) 119 } 120 121 urlToReg := getConsumerUrlToRegistry(url) 122 err := dir.registry.Register(urlToReg) 123 if err != nil { 124 logger.Errorf("consumer service %v register registry %v error, error message is %s", 125 url.String(), dir.registry.GetURL().String(), err.Error()) 126 } 127 }() 128 129 return nil 130 } 131 132 // Notify monitor changes from registry,and update the cacheServices 133 func (dir *RegistryDirectory) Notify(event *registry.ServiceEvent) { 134 if event == nil { 135 return 136 } 137 start := time.Now() 138 dir.refreshInvokers(event) 139 metrics.Publish(metricsRegistry.NewNotifyEvent(start)) 140 } 141 142 // NotifyAll notify the events that are complete Service Event List. 143 // After notify the address, the callback func will be invoked. 144 func (dir *RegistryDirectory) NotifyAll(events []*registry.ServiceEvent, callback func()) { 145 go dir.refreshAllInvokers(events, callback) 146 } 147 148 // refreshInvokers refreshes service's events. 149 func (dir *RegistryDirectory) refreshInvokers(event *registry.ServiceEvent) { 150 if event != nil { 151 logger.Debugf("refresh invokers with %+v", event) 152 } else { 153 logger.Debug("refresh invokers with nil") 154 } 155 156 var oldInvoker []protocol.Invoker 157 if event != nil { 158 oldInvoker, _ = dir.cacheInvokerByEvent(event) 159 } 160 dir.setNewInvokers() 161 for _, v := range oldInvoker { 162 if v != nil { 163 v.Destroy() 164 } 165 } 166 } 167 168 // refreshAllInvokers the argument is the complete list of the service events, we can safely assume any cached invoker 169 // not in the incoming list can be removed. The Action of serviceEvent should be EventTypeUpdate or EventTypeAdd. 170 func (dir *RegistryDirectory) refreshAllInvokers(events []*registry.ServiceEvent, callback func()) { 171 var ( 172 oldInvokers []protocol.Invoker 173 addEvents []*registry.ServiceEvent 174 ) 175 dir.overrideUrl(dir.GetDirectoryUrl()) 176 referenceUrl := dir.GetDirectoryUrl().SubURL 177 178 // loop the events to check the Action should be EventTypeUpdate. 179 for _, event := range events { 180 if event.Action != remoting.EventTypeUpdate && event.Action != remoting.EventTypeAdd { 181 panic("Your implements of register center is wrong, " + 182 "please check the Action of ServiceEvent should be EventTypeUpdate") 183 } 184 // Originally it will Merge URL many times, now we just execute once. 185 // MergeURL is executed once and put the result into Event. After this, the key will get from Event.Key(). 186 newUrl := dir.convertUrl(event) 187 newUrl = common.MergeURL(newUrl, referenceUrl) 188 dir.overrideUrl(newUrl) 189 event.Update(newUrl) 190 } 191 // After notify all addresses, do some callback. 192 defer callback() 193 func() { 194 // this lock is work at batch update of InvokeCache 195 dir.registerLock.Lock() 196 defer dir.registerLock.Unlock() 197 // get need clear invokers from original invoker list 198 dir.cacheInvokersMap.Range(func(k, v interface{}) bool { 199 if !dir.eventMatched(k.(string), events) { 200 // delete unused invoker from cache 201 if invoker := dir.uncacheInvokerWithKey(k.(string)); invoker != nil { 202 oldInvokers = append(oldInvokers, invoker) 203 } 204 } 205 return true 206 }) 207 // get need add invokers from events 208 for _, event := range events { 209 // Get the key from Event.Key() 210 if _, ok := dir.cacheInvokersMap.Load(event.Key()); !ok { 211 addEvents = append(addEvents, event) 212 } 213 } 214 // loop the serviceEvents 215 for _, event := range addEvents { 216 logger.Debugf("[Registry Directory] registry changed, result{%s}", event) 217 if event != nil && event.Service != nil { 218 logger.Infof("[Registry Directory] selector add service url{%s}", event.Service.String()) 219 } 220 if event != nil && event.Service != nil && constant.RouterProtocol == event.Service.Protocol { 221 dir.configRouters() 222 } 223 if oldInvoker, _ := dir.doCacheInvoker(event.Service, event); oldInvoker != nil { 224 oldInvokers = append(oldInvokers, oldInvoker) 225 } 226 } 227 }() 228 dir.setNewInvokers() 229 // destroy unused invokers 230 for _, invoker := range oldInvokers { 231 go invoker.Destroy() 232 } 233 } 234 235 // eventMatched checks if a cached invoker appears in the incoming invoker list, if no, then it is safe to remove. 236 func (dir *RegistryDirectory) eventMatched(key string, events []*registry.ServiceEvent) bool { 237 for _, event := range events { 238 if dir.invokerCacheKey(event) == key { 239 return true 240 } 241 } 242 return false 243 } 244 245 // invokerCacheKey generates the key in the cache for a given ServiceEvent. 246 func (dir *RegistryDirectory) invokerCacheKey(event *registry.ServiceEvent) string { 247 // If the url is merged, then return Event.Key() directly. 248 if event.Updated() { 249 return event.Key() 250 } 251 referenceUrl := dir.GetDirectoryUrl().SubURL 252 newUrl := common.MergeURL(event.Service, referenceUrl) 253 event.Update(newUrl) 254 return event.Key() 255 } 256 257 // setNewInvokers groups the invokers from the cache first, then set the result to both directory and router chain. 258 func (dir *RegistryDirectory) setNewInvokers() { 259 newInvokers := dir.toGroupInvokers() 260 dir.invokersLock.Lock() 261 defer dir.invokersLock.Unlock() 262 dir.cacheInvokers = newInvokers 263 dir.RouterChain().SetInvokers(newInvokers) 264 } 265 266 // cacheInvokerByEvent caches invokers from the service event 267 func (dir *RegistryDirectory) cacheInvokerByEvent(event *registry.ServiceEvent) ([]protocol.Invoker, error) { 268 // judge is override or others 269 if event != nil { 270 271 switch event.Action { 272 case remoting.EventTypeAdd, remoting.EventTypeUpdate: 273 u := dir.convertUrl(event) 274 logger.Infof("[Registry Directory] selector add service url{%s}", event.Service) 275 if u != nil && constant.RouterProtocol == u.Protocol { 276 dir.configRouters() 277 } 278 return []protocol.Invoker{dir.cacheInvoker(u, event)}, nil 279 case remoting.EventTypeDel: 280 logger.Infof("[Registry Directory] selector delete service url{%s}", event.Service) 281 return dir.uncacheInvoker(event), nil 282 default: 283 return nil, fmt.Errorf("illegal event type: %v", event.Action) 284 } 285 } 286 return nil, nil 287 } 288 289 // configRouters configures dynamic routers into the router chain, but, the current impl is incorrect, see FIXME above. 290 func (dir *RegistryDirectory) configRouters() { 291 } 292 293 // convertUrl processes override:// and router:// 294 func (dir *RegistryDirectory) convertUrl(res *registry.ServiceEvent) *common.URL { 295 ret := res.Service 296 if ret.Protocol == constant.OverrideProtocol || // 1.for override url in 2.6.x 297 ret.GetParam(constant.CategoryKey, constant.DefaultCategory) == constant.ConfiguratorsCategory { 298 dir.configurators = append(dir.configurators, extension.GetDefaultConfigurator(ret)) 299 ret = nil 300 } else if ret.Protocol == constant.RouterProtocol || // 2.for router 301 ret.GetParam(constant.CategoryKey, constant.DefaultCategory) == constant.RouterCategory { 302 ret = nil 303 } 304 return ret 305 } 306 307 func (dir *RegistryDirectory) toGroupInvokers() []protocol.Invoker { 308 groupInvokersMap := make(map[string][]protocol.Invoker) 309 310 dir.cacheInvokersMap.Range(func(key, value interface{}) bool { 311 invoker := value.(protocol.Invoker) 312 group := invoker.GetURL().GetParam(constant.GroupKey, "") 313 groupInvokersMap[group] = append(groupInvokersMap[group], invoker) 314 return true 315 }) 316 317 groupInvokersList := make([]protocol.Invoker, 0, len(groupInvokersMap)) 318 if len(groupInvokersMap) == 1 { 319 // len is 1 it means no group setting ,so do not need cluster again 320 for _, invokers := range groupInvokersMap { 321 groupInvokersList = invokers 322 } 323 } else { 324 for _, invokers := range groupInvokersMap { 325 staticDir := static.NewDirectory(invokers) 326 clusterKey := dir.GetURL().SubURL.GetParam(constant.ClusterKey, constant.DefaultCluster) 327 cluster, err := extension.GetCluster(clusterKey) 328 if err != nil { 329 panic(err) 330 } 331 err = staticDir.BuildRouterChain(invokers) 332 if err != nil { 333 logger.Error(err) 334 continue 335 } 336 groupInvokersList = append(groupInvokersList, cluster.Join(staticDir)) 337 } 338 } 339 340 return groupInvokersList 341 } 342 343 func (dir *RegistryDirectory) uncacheInvokerWithClusterID(clusterID string) []protocol.Invoker { 344 logger.Debugf("All service will be deleted in cache invokers with clusterID %s!", clusterID) 345 invokerKeys := make([]string, 0) 346 dir.cacheInvokersMap.Range(func(key, cacheInvoker interface{}) bool { 347 if cacheInvoker.(protocol.Invoker).GetURL().GetParam(constant.MeshClusterIDKey, "") == clusterID { 348 invokerKeys = append(invokerKeys, key.(string)) 349 } 350 return true 351 }) 352 uncachedInvokers := make([]protocol.Invoker, 0) 353 for _, v := range invokerKeys { 354 uncachedInvokers = append(uncachedInvokers, dir.uncacheInvokerWithKey(v)) 355 } 356 return uncachedInvokers 357 } 358 359 // uncacheInvoker will return abandoned Invoker, if no Invoker to be abandoned, return nil 360 func (dir *RegistryDirectory) uncacheInvoker(event *registry.ServiceEvent) []protocol.Invoker { 361 defer metrics.Publish(metricsRegistry.NewDirectoryEvent(metricsRegistry.NumDisableTotal)) 362 if clusterID := event.Service.GetParam(constant.MeshClusterIDKey, ""); event.Service.Location == constant.MeshAnyAddrMatcher && clusterID != "" { 363 dir.uncacheInvokerWithClusterID(clusterID) 364 } 365 return []protocol.Invoker{dir.uncacheInvokerWithKey(event.Key())} 366 } 367 368 func (dir *RegistryDirectory) uncacheInvokerWithKey(key string) protocol.Invoker { 369 logger.Debugf("service will be deleted in cache invokers: invokers key is %s!", key) 370 protocol.RemoveUrlKeyUnhealthyStatus(key) 371 if cacheInvoker, ok := dir.cacheInvokersMap.Load(key); ok { 372 dir.cacheInvokersMap.Delete(key) 373 return cacheInvoker.(protocol.Invoker) 374 } 375 return nil 376 } 377 378 // cacheInvoker will return abandoned Invoker,if no Invoker to be abandoned,return nil 379 func (dir *RegistryDirectory) cacheInvoker(url *common.URL, event *registry.ServiceEvent) protocol.Invoker { 380 dir.overrideUrl(dir.GetDirectoryUrl()) 381 referenceUrl := dir.GetDirectoryUrl().SubURL 382 383 if url == nil && dir.cacheOriginUrl != nil { 384 url = dir.cacheOriginUrl 385 } else { 386 dir.cacheOriginUrl = url 387 } 388 if url == nil { 389 logger.Error("URL is nil ,pls check if service url is subscribe successfully!") 390 return nil 391 } 392 // check the url's protocol is equal to the protocol which is configured in reference config or referenceUrl is not care about protocol 393 if url.Protocol == referenceUrl.Protocol || referenceUrl.Protocol == "" { 394 newUrl := common.MergeURL(url, referenceUrl) 395 dir.overrideUrl(newUrl) 396 event.Update(newUrl) 397 if v, ok := dir.doCacheInvoker(newUrl, event); ok { 398 return v 399 } 400 } 401 return nil 402 } 403 404 func (dir *RegistryDirectory) doCacheInvoker(newUrl *common.URL, event *registry.ServiceEvent) (protocol.Invoker, bool) { 405 key := event.Key() 406 if cacheInvoker, ok := dir.cacheInvokersMap.Load(key); !ok { 407 logger.Debugf("service will be added in cache invokers: invokers url is %s!", newUrl) 408 newInvoker := extension.GetProtocol(protocolwrapper.FILTER).Refer(newUrl) 409 if newInvoker != nil { 410 dir.cacheInvokersMap.Store(key, newInvoker) 411 } else { 412 logger.Warnf("service will be added in cache invokers fail, result is null, invokers url is %+v", newUrl.String()) 413 } 414 } else { 415 metrics.Publish(metricsRegistry.NewDirectoryEvent(metricsRegistry.NumValidTotal)) 416 // if cached invoker has the same URL with the new URL, then no need to re-refer, and no need to destroy 417 // the old invoker. 418 if common.GetCompareURLEqualFunc()(newUrl, cacheInvoker.(protocol.Invoker).GetURL()) { 419 return nil, true 420 } 421 422 logger.Debugf("service will be updated in cache invokers: new invoker url is %s, old invoker url is %s", newUrl, cacheInvoker.(protocol.Invoker).GetURL()) 423 newInvoker := extension.GetProtocol(protocolwrapper.FILTER).Refer(newUrl) 424 if newInvoker != nil { 425 dir.cacheInvokersMap.Store(key, newInvoker) 426 return cacheInvoker.(protocol.Invoker), true 427 } else { 428 logger.Warnf("service will be updated in cache invokers fail, result is null, invokers url is %+v", newUrl.String()) 429 } 430 } 431 return nil, false 432 } 433 434 // List selected protocol invokers from the directory 435 func (dir *RegistryDirectory) List(invocation protocol.Invocation) []protocol.Invoker { 436 routerChain := dir.RouterChain() 437 438 if routerChain == nil { 439 dir.invokersLock.RLock() 440 defer dir.invokersLock.RUnlock() 441 return dir.cacheInvokers 442 } 443 return routerChain.Route(dir.consumerURL, invocation) 444 } 445 446 // IsAvailable whether the directory is available 447 func (dir *RegistryDirectory) IsAvailable() bool { 448 if dir.Directory.IsDestroyed() { 449 return false 450 } 451 452 for _, ivk := range dir.cacheInvokers { 453 if ivk.IsAvailable() { 454 return true 455 } 456 } 457 metrics.Publish(metricsRegistry.NewDirectoryEvent(metricsRegistry.NumToReconnectTotal)) 458 return false 459 } 460 461 // Destroy method 462 func (dir *RegistryDirectory) Destroy() { 463 // TODO:unregister & unsubscribe 464 dir.Directory.DoDestroy(func() { 465 if dir.RegisteredUrl != nil { 466 err := dir.registry.UnRegister(dir.RegisteredUrl) 467 if err != nil { 468 logger.Warnf("Unregister consumer url failed, %s", dir.RegisteredUrl.String(), err) 469 } 470 } 471 472 if dir.SubscribedUrl != nil { 473 err := dir.registry.UnSubscribe(dir.SubscribedUrl, dir) 474 if err != nil { 475 logger.Warnf("Unsubscribe consumer url failed, %s", dir.RegisteredUrl.String(), err) 476 } 477 } 478 479 invokers := dir.cacheInvokers 480 dir.cacheInvokers = []protocol.Invoker{} 481 for _, ivk := range invokers { 482 ivk.Destroy() 483 } 484 }) 485 metrics.Publish(metricsRegistry.NewDirectoryEvent(metricsRegistry.NumAllDec)) 486 } 487 488 func (dir *RegistryDirectory) overrideUrl(targetUrl *common.URL) { 489 doOverrideUrl(dir.configurators, targetUrl) 490 doOverrideUrl(dir.consumerConfigurationListener.Configurators(), targetUrl) 491 doOverrideUrl(dir.referenceConfigurationListener.Configurators(), targetUrl) 492 } 493 494 func (dir *RegistryDirectory) getConsumerUrl(c *common.URL) *common.URL { 495 processID := fmt.Sprintf("%d", os.Getpid()) 496 localIP := common.GetLocalIp() 497 498 params := url.Values{} 499 c.RangeParams(func(key, value string) bool { 500 params.Add(key, value) 501 return true 502 }) 503 504 params.Add("pid", processID) 505 params.Add("ip", localIP) 506 params.Add("protocol", c.Protocol) 507 508 return common.NewURLWithOptions(common.WithProtocol("consumer"), common.WithIp(localIP), common.WithPath(c.Path), 509 common.WithParams(params)) 510 } 511 512 func doOverrideUrl(configurators []config_center.Configurator, targetUrl *common.URL) { 513 for _, v := range configurators { 514 v.Configure(targetUrl) 515 } 516 } 517 518 type referenceConfigurationListener struct { 519 registry.BaseConfigurationListener 520 directory *RegistryDirectory 521 url *common.URL 522 } 523 524 func newReferenceConfigurationListener(dir *RegistryDirectory, url *common.URL) *referenceConfigurationListener { 525 listener := &referenceConfigurationListener{directory: dir, url: url} 526 listener.InitWith( 527 url.ColonSeparatedKey()+constant.ConfiguratorSuffix, 528 listener, 529 extension.GetDefaultConfiguratorFunc(), 530 ) 531 return listener 532 } 533 534 // Process handle events and update Invokers 535 func (l *referenceConfigurationListener) Process(event *config_center.ConfigChangeEvent) { 536 l.BaseConfigurationListener.Process(event) 537 // FIXME: this doesn't trigger dir.overrideUrl() 538 l.directory.refreshInvokers(nil) 539 } 540 541 type consumerConfigurationListener struct { 542 registry.BaseConfigurationListener 543 listeners []registry.NotifyListener 544 directory *RegistryDirectory 545 } 546 547 func newConsumerConfigurationListener(dir *RegistryDirectory) *consumerConfigurationListener { 548 listener := &consumerConfigurationListener{directory: dir} 549 application := config.GetRootConfig().Application 550 listener.InitWith( 551 application.Name+constant.ConfiguratorSuffix, 552 listener, 553 extension.GetDefaultConfiguratorFunc(), 554 ) 555 return listener 556 } 557 558 func (l *consumerConfigurationListener) addNotifyListener(listener registry.NotifyListener) { 559 l.listeners = append(l.listeners, listener) 560 } 561 562 // Process handles events from Configuration Center and update Invokers 563 func (l *consumerConfigurationListener) Process(event *config_center.ConfigChangeEvent) { 564 l.BaseConfigurationListener.Process(event) 565 // FIXME: this doesn't trigger dir.overrideUrl() 566 l.directory.refreshInvokers(nil) 567 } 568 569 // ServiceDiscoveryRegistryDirectory implementation of Directory: 570 // Invoker list returned from this Directory's list method have been filtered by Routers 571 type ServiceDiscoveryRegistryDirectory struct { 572 *base.Directory 573 *RegistryDirectory 574 } 575 576 // NewServiceDiscoveryRegistryDirectory will create a new ServiceDiscoveryRegistryDirectory 577 func NewServiceDiscoveryRegistryDirectory(url *common.URL, registry registry.Registry) (directory.Directory, error) { 578 dic, err := NewRegistryDirectory(url, registry) 579 registryDirectory, _ := dic.(*RegistryDirectory) 580 return &ServiceDiscoveryRegistryDirectory{ 581 Directory: registryDirectory.Directory, 582 RegistryDirectory: registryDirectory, 583 }, err 584 } 585 586 // Subscribe do subscribe from registry 587 func (dir *ServiceDiscoveryRegistryDirectory) Subscribe(url *common.URL) error { 588 if err := dir.registry.Subscribe(url, dir); err != nil { 589 logger.Error("registry.Subscribe(url:%v, dir:%v) = error:%v", url, dir, err) 590 return err 591 } 592 593 urlToReg := getConsumerUrlToRegistry(url) 594 err := dir.RegistryDirectory.registry.Register(urlToReg) 595 if err != nil { 596 logger.Errorf("consumer service %v register registry %v error, error message is %s", 597 url.String(), dir.registry.GetURL().String(), err.Error()) 598 return err 599 } 600 return nil 601 } 602 603 // List selected protocol invokers from the directory 604 func (dir *ServiceDiscoveryRegistryDirectory) List(invocation protocol.Invocation) []protocol.Invoker { 605 return dir.RegistryDirectory.List(invocation) 606 } 607 608 func getConsumerUrlToRegistry(url *common.URL) *common.URL { 609 // if developer define registry port and ip, use it first. 610 if ipToRegistry := os.Getenv(constant.DubboIpToRegistryKey); len(ipToRegistry) > 0 { 611 url.Ip = ipToRegistry 612 } else { 613 url.Ip = common.GetLocalIp() 614 } 615 if portToRegistry := os.Getenv(constant.DubboPortToRegistryKey); len(portToRegistry) > 0 { 616 url.Port = portToRegistry 617 } 618 return url 619 }