dubbo.apache.org/dubbo-go/v3@v3.1.1/registry/polaris/service_discovery.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  	"sync"
    23  )
    24  
    25  import (
    26  	gxset "github.com/dubbogo/gost/container/set"
    27  	gxpage "github.com/dubbogo/gost/hash/page"
    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  func init() {
    46  	extension.SetServiceDiscovery(constant.PolarisKey, newPolarisServiceDiscovery)
    47  }
    48  
    49  // newPolarisServiceDiscovery will create new service discovery instance
    50  func newPolarisServiceDiscovery(url *common.URL) (registry.ServiceDiscovery, error) {
    51  	discoveryURL := common.NewURLWithOptions(
    52  		common.WithParams(url.GetParams()),
    53  		common.WithParamsValue(constant.TimeoutKey, url.GetParam(constant.RegistryTimeoutKey, constant.DefaultRegTimeout)),
    54  		common.WithParamsValue(constant.PolarisServiceToken, url.Password),
    55  		common.WithParamsValue(constant.RegistryNamespaceKey, url.GetParam(constant.RegistryNamespaceKey, constant.PolarisDefaultNamespace)))
    56  	discoveryURL.Location = url.Location
    57  	discoveryURL.Password = url.Password
    58  
    59  	if err := polaris.InitSDKContext(url); err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	providerApi, err := polaris.GetProviderAPI()
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	consumerApi, err := polaris.GetConsumerAPI()
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	if err != nil {
    74  		return nil, perrors.WithMessage(err, "create polaris namingClient failed.")
    75  	}
    76  
    77  	descriptor := fmt.Sprintf("polaris-service-discovery[%s]", discoveryURL.Location)
    78  
    79  	newInstance := &polarisServiceDiscovery{
    80  		namespace:         discoveryURL.GetParam(constant.RegistryNamespaceKey, constant.PolarisDefaultNamespace),
    81  		descriptor:        descriptor,
    82  		consumer:          consumerApi,
    83  		provider:          providerApi,
    84  		services:          gxset.NewSet(),
    85  		registryInstances: make(map[string]*PolarisInstanceInfo),
    86  		watchers:          make(map[string]*PolarisServiceWatcher),
    87  	}
    88  	return newInstance, nil
    89  }
    90  
    91  type polarisServiceDiscovery struct {
    92  	namespace         string
    93  	descriptor        string
    94  	provider          api.ProviderAPI
    95  	consumer          api.ConsumerAPI
    96  	services          *gxset.HashSet
    97  	instanceLock      sync.RWMutex
    98  	registryInstances map[string]*PolarisInstanceInfo
    99  	watchers          map[string]*PolarisServiceWatcher
   100  	listenerLock      sync.RWMutex
   101  }
   102  
   103  // Destroy destroy polarisServiceDiscovery, will do unregister all ServiceInstance
   104  // and close polaris.ConsumerAPI and polaris.ProviderAPI
   105  func (polaris *polarisServiceDiscovery) Destroy() error {
   106  	for _, inst := range polaris.registryInstances {
   107  		err := polaris.Unregister(inst.instance)
   108  		logger.Infof("Unregister polaris instance:%+v", inst)
   109  		if err != nil {
   110  			logger.Errorf("Unregister polaris instance:%+v, err:%+v", inst, err)
   111  		}
   112  	}
   113  	polaris.provider.Destroy()
   114  	polaris.consumer.Destroy()
   115  	return nil
   116  }
   117  
   118  // Register do register for ServiceInstance
   119  func (polaris *polarisServiceDiscovery) Register(instance registry.ServiceInstance) error {
   120  
   121  	ins := convertToRegisterInstance(polaris.namespace, instance)
   122  	resp, err := polaris.provider.RegisterInstance(ins)
   123  	if err != nil {
   124  		return perrors.WithMessage(err, "could not register the instance. "+instance.GetServiceName())
   125  	}
   126  
   127  	if resp.Existed {
   128  		logger.Warnf("instance already regist, namespace:%+v, service:%+v, host:%+v, port:%+v",
   129  			polaris.namespace, instance.GetServiceName(), instance.GetHost(), instance.GetPort())
   130  	}
   131  
   132  	polaris.instanceLock.Lock()
   133  	defer polaris.instanceLock.Unlock()
   134  
   135  	polaris.registryInstances[getInstanceKey(polaris.namespace, instance)] = &PolarisInstanceInfo{
   136  		instance: instance,
   137  	}
   138  	polaris.services.Add(instance.GetServiceName())
   139  
   140  	return nil
   141  }
   142  
   143  // Update update ServiceInstance info
   144  func (polaris *polarisServiceDiscovery) Update(instance registry.ServiceInstance) error {
   145  	err := polaris.Unregister(instance)
   146  	if err != nil {
   147  		return perrors.WithStack(err)
   148  	}
   149  	polaris.services.Add(instance.GetServiceName())
   150  	return polaris.Register(instance)
   151  }
   152  
   153  // Unregister do Unregister for ServiceInstance
   154  func (polaris *polarisServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
   155  
   156  	func() {
   157  		polaris.instanceLock.Lock()
   158  		defer polaris.instanceLock.Unlock()
   159  		key := getInstanceKey(polaris.namespace, instance)
   160  		if _, exist := polaris.registryInstances[key]; exist {
   161  			delete(polaris.registryInstances, key)
   162  		}
   163  	}()
   164  
   165  	err := polaris.provider.Deregister(convertToDeregisterInstance(polaris.namespace, instance))
   166  	if err != nil {
   167  		return perrors.WithMessage(err, "Could not unregister the instance. "+instance.GetServiceName())
   168  	}
   169  
   170  	polaris.services.Remove(instance.GetServiceName())
   171  	return nil
   172  }
   173  
   174  func (polaris *polarisServiceDiscovery) GetDefaultPageSize() int {
   175  	return registry.DefaultPageSize
   176  }
   177  
   178  func (polaris *polarisServiceDiscovery) GetServices() *gxset.HashSet {
   179  	return polaris.services
   180  }
   181  
   182  // GetInstances will return all service instances with serviceName
   183  func (polaris *polarisServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
   184  	resp, err := polaris.consumer.GetAllInstances(&api.GetAllInstancesRequest{
   185  		GetAllInstancesRequest: model.GetAllInstancesRequest{
   186  			Service:   serviceName,
   187  			Namespace: polaris.namespace,
   188  		},
   189  	})
   190  
   191  	if err != nil {
   192  		logger.Errorf("Could not query the instances for service: %+v . It happened err %+v", serviceName, err)
   193  		return make([]registry.ServiceInstance, 0)
   194  	}
   195  	res := make([]registry.ServiceInstance, 0, len(resp.Instances))
   196  	for _, ins := range resp.Instances {
   197  		metadata := ins.GetMetadata()
   198  		res = append(res, &registry.DefaultServiceInstance{
   199  			ID:          ins.GetId(),
   200  			ServiceName: serviceName,
   201  			Host:        ins.GetHost(),
   202  			Port:        int(ins.GetPort()),
   203  			Enable:      !ins.IsIsolated(),
   204  			Healthy:     ins.IsHealthy(),
   205  			Metadata:    metadata,
   206  		})
   207  	}
   208  	return res
   209  }
   210  
   211  // GetInstancesByPage will return a page containing instances of ServiceInstance with the serviceName
   212  // the page will start at offset
   213  func (polaris *polarisServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
   214  	all := polaris.GetInstances(serviceName)
   215  	res := make([]interface{}, 0, pageSize)
   216  	for i := offset; i < len(all) && i < offset+pageSize; i++ {
   217  		res = append(res, all[i])
   218  	}
   219  	return gxpage.NewPage(offset, pageSize, res, len(all))
   220  }
   221  
   222  // GetHealthyInstancesByPage will return a page containing instances of ServiceInstance.
   223  // The param healthy indices that the instance should be healthy or not.
   224  // The page will start at offset
   225  func (polaris *polarisServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
   226  	all := polaris.GetInstances(serviceName)
   227  	res := make([]interface{}, 0, pageSize)
   228  	// could not use res = all[a:b] here because the res should be []interface{}, not []ServiceInstance
   229  	var (
   230  		i     = offset
   231  		count = 0
   232  	)
   233  	for i < len(all) && count < pageSize {
   234  		ins := all[i]
   235  		if ins.IsHealthy() == healthy {
   236  			res = append(res, all[i])
   237  			count++
   238  		}
   239  		i++
   240  	}
   241  	return gxpage.NewPage(offset, pageSize, res, len(all))
   242  }
   243  
   244  // GetRequestInstances get all instances by the specified service names
   245  func (polaris *polarisServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
   246  	res := make(map[string]gxpage.Pager, len(serviceNames))
   247  	for _, name := range serviceNames {
   248  		res[name] = polaris.GetInstancesByPage(name, offset, requestedSize)
   249  	}
   250  	return res
   251  }
   252  
   253  // AddListener add listener for ServiceInstancesChangedListener
   254  func (polaris *polarisServiceDiscovery) AddListener(listener registry.ServiceInstancesChangedListener) error {
   255  
   256  	for _, val := range listener.GetServiceNames().Values() {
   257  		serviceName := val.(string)
   258  		watcher, err := polaris.createPolarisWatcherIfAbsent(serviceName)
   259  		if err != nil {
   260  			return err
   261  		}
   262  
   263  		watcher.AddSubscriber(func(et remoting.EventType, instances []model.Instance) {
   264  			dubboInstances := make([]registry.ServiceInstance, 0, len(instances))
   265  			for _, instance := range instances {
   266  				dubboInstances = append(dubboInstances, &registry.DefaultServiceInstance{
   267  					ID:          instance.GetId(),
   268  					ServiceName: instance.GetService(),
   269  					Host:        instance.GetHost(),
   270  					Port:        int(instance.GetPort()),
   271  					Enable:      !instance.IsIsolated(),
   272  					Healthy:     instance.IsHealthy(),
   273  					Metadata:    instance.GetMetadata(),
   274  					GroupName:   instance.GetMetadata()[constant.PolarisDubboGroup],
   275  				})
   276  			}
   277  
   278  			listener.OnEvent(registry.NewServiceInstancesChangedEvent(serviceName, dubboInstances))
   279  		})
   280  	}
   281  
   282  	return nil
   283  }
   284  
   285  // createPolarisWatcherIfAbsent Calculate whether the corresponding PolarisWatcher needs to be created,
   286  // if it does not exist, create one, otherwise return the existing one
   287  func (polaris *polarisServiceDiscovery) createPolarisWatcherIfAbsent(serviceName string) (*PolarisServiceWatcher, error) {
   288  
   289  	polaris.listenerLock.Lock()
   290  	defer polaris.listenerLock.Unlock()
   291  
   292  	if _, exist := polaris.watchers[serviceName]; !exist {
   293  		subscribeParam := &api.WatchServiceRequest{
   294  			WatchServiceRequest: model.WatchServiceRequest{
   295  				Key: model.ServiceKey{
   296  					Namespace: polaris.namespace,
   297  					Service:   serviceName,
   298  				},
   299  			},
   300  		}
   301  
   302  		watcher, err := newPolarisWatcher(subscribeParam, polaris.consumer)
   303  		if err != nil {
   304  			return nil, err
   305  		}
   306  		polaris.watchers[serviceName] = watcher
   307  	}
   308  
   309  	return polaris.watchers[serviceName], nil
   310  }
   311  
   312  // String retuen descriptor
   313  func (polaris *polarisServiceDiscovery) String() string {
   314  	return polaris.descriptor
   315  }
   316  
   317  func convertToRegisterInstance(namespace string, instance registry.ServiceInstance) *api.InstanceRegisterRequest {
   318  
   319  	var (
   320  		health      = instance.IsHealthy()
   321  		isolate     = instance.IsEnable()
   322  		ttl         = 5
   323  		protocolVal = string(constant.Dubbo)
   324  	)
   325  
   326  	return &api.InstanceRegisterRequest{
   327  		InstanceRegisterRequest: model.InstanceRegisterRequest{
   328  			Service:   instance.GetServiceName(),
   329  			Namespace: namespace,
   330  			Host:      instance.GetHost(),
   331  			Port:      instance.GetPort(),
   332  			Protocol:  &protocolVal,
   333  			Metadata:  instance.GetMetadata(),
   334  			Healthy:   &health,
   335  			Isolate:   &isolate,
   336  			TTL:       &ttl,
   337  		},
   338  	}
   339  }
   340  
   341  func convertToDeregisterInstance(namespace string, instance registry.ServiceInstance) *api.InstanceDeRegisterRequest {
   342  	return &api.InstanceDeRegisterRequest{
   343  		InstanceDeRegisterRequest: model.InstanceDeRegisterRequest{
   344  			Service:   instance.GetServiceName(),
   345  			Namespace: namespace,
   346  			Host:      instance.GetHost(),
   347  			Port:      instance.GetPort(),
   348  		},
   349  	}
   350  }