dubbo.apache.org/dubbo-go/v3@v3.1.1/cluster/router/polaris/router.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  	"context"
    22  	"errors"
    23  	"fmt"
    24  	"strings"
    25  	"sync"
    26  	"time"
    27  )
    28  
    29  import (
    30  	"github.com/dubbogo/gost/log/logger"
    31  
    32  	"github.com/polarismesh/polaris-go"
    33  	"github.com/polarismesh/polaris-go/pkg/model"
    34  	v1 "github.com/polarismesh/polaris-go/pkg/model/pb/v1"
    35  )
    36  
    37  import (
    38  	"dubbo.apache.org/dubbo-go/v3/cluster/router"
    39  	"dubbo.apache.org/dubbo-go/v3/common"
    40  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    41  	"dubbo.apache.org/dubbo-go/v3/config"
    42  	"dubbo.apache.org/dubbo-go/v3/protocol"
    43  	remotingpolaris "dubbo.apache.org/dubbo-go/v3/remoting/polaris"
    44  	"dubbo.apache.org/dubbo-go/v3/remoting/polaris/parser"
    45  )
    46  
    47  var (
    48  	_ router.PriorityRouter = (*polarisRouter)(nil)
    49  )
    50  
    51  var (
    52  	ErrorPolarisServiceRouteRuleEmpty = errors.New("service route rule is empty")
    53  )
    54  
    55  func newPolarisRouter() (*polarisRouter, error) {
    56  	if err := remotingpolaris.Check(); errors.Is(err, remotingpolaris.ErrorNoOpenPolarisAbility) {
    57  		return &polarisRouter{
    58  			openRoute: false,
    59  		}, nil
    60  	}
    61  
    62  	routerAPI, err := remotingpolaris.GetRouterAPI()
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	consumerAPI, err := remotingpolaris.GetConsumerAPI()
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	return &polarisRouter{
    72  		openRoute:   true,
    73  		routerAPI:   routerAPI,
    74  		consumerAPI: consumerAPI,
    75  	}, nil
    76  }
    77  
    78  type polarisRouter struct {
    79  	openRoute bool
    80  
    81  	routerAPI   polaris.RouterAPI
    82  	consumerAPI polaris.ConsumerAPI
    83  
    84  	cancel context.CancelFunc
    85  
    86  	lock      sync.RWMutex
    87  	instances map[string]model.Instance
    88  }
    89  
    90  // Route Determine the target invokers list.
    91  func (p *polarisRouter) Route(invokers []protocol.Invoker, url *common.URL,
    92  	invoaction protocol.Invocation) []protocol.Invoker {
    93  
    94  	if !p.openRoute {
    95  		logger.Debug("[Router][Polaris] not open polaris route ability")
    96  		return invokers
    97  	}
    98  
    99  	if len(invokers) == 0 {
   100  		logger.Warn("[Router][Polaris] invokers from previous router is empty")
   101  		return invokers
   102  	}
   103  
   104  	service := getService(url)
   105  	instanceMap := p.buildInstanceMap(service)
   106  	if len(instanceMap) == 0 {
   107  		return invokers
   108  	}
   109  
   110  	invokersMap := make(map[string]protocol.Invoker, len(invokers))
   111  	targetIns := make([]model.Instance, 0, len(invokers))
   112  	for i := range invokers {
   113  		invoker := invokers[i]
   114  		instanceID := invoker.GetURL().GetParam(constant.PolarisInstanceID, "")
   115  		if len(instanceID) == 0 {
   116  			continue
   117  		}
   118  		invokersMap[instanceID] = invoker
   119  		if val, ok := instanceMap[instanceID]; ok {
   120  			targetIns = append(targetIns, val)
   121  		}
   122  	}
   123  
   124  	req, err := p.buildRouteRequest(service, url, invoaction)
   125  	if err != nil {
   126  		return invokers
   127  	}
   128  	req.DstInstances = model.NewDefaultServiceInstances(model.ServiceInfo{
   129  		Service:   service,
   130  		Namespace: remotingpolaris.GetNamespace(),
   131  	}, targetIns)
   132  
   133  	resp, err := p.routerAPI.ProcessRouters(&req)
   134  	if err != nil {
   135  		return invokers
   136  	}
   137  
   138  	ret := make([]protocol.Invoker, 0, len(resp.GetInstances()))
   139  	for i := range resp.GetInstances() {
   140  		if val, ok := invokersMap[resp.GetInstances()[i].GetId()]; ok {
   141  			ret = append(ret, val)
   142  		}
   143  	}
   144  
   145  	return ret
   146  }
   147  
   148  func getService(url *common.URL) string {
   149  	applicationMode := false
   150  	for _, item := range config.GetRootConfig().Registries {
   151  		if item.Protocol == constant.PolarisKey {
   152  			applicationMode = item.RegistryType == constant.ServiceKey
   153  		}
   154  	}
   155  
   156  	service := url.Interface()
   157  	if applicationMode {
   158  		service = config.GetApplicationConfig().Name
   159  	}
   160  
   161  	return service
   162  }
   163  
   164  func (p *polarisRouter) buildRouteRequest(svc string, url *common.URL,
   165  	invocation protocol.Invocation) (polaris.ProcessRoutersRequest, error) {
   166  
   167  	routeReq := polaris.ProcessRoutersRequest{
   168  		ProcessRoutersRequest: model.ProcessRoutersRequest{
   169  			SourceService: model.ServiceInfo{
   170  				Metadata: map[string]string{},
   171  			},
   172  		},
   173  	}
   174  
   175  	attachement := invocation.Attachments()
   176  	arguments := invocation.Arguments()
   177  
   178  	labels, err := p.buildTrafficLabels(svc)
   179  	if err != nil {
   180  		return polaris.ProcessRoutersRequest{}, err
   181  	}
   182  
   183  	for i := range labels {
   184  		label := labels[i]
   185  		if strings.Compare(label, model.LabelKeyPath) == 0 {
   186  			routeReq.AddArguments(model.BuildPathArgument(getInvokeMethod(url, invocation)))
   187  			continue
   188  		}
   189  		if strings.HasPrefix(label, model.LabelKeyHeader) {
   190  			if val, ok := attachement[strings.TrimPrefix(label, model.LabelKeyHeader)]; ok {
   191  				routeReq.SourceService.Metadata[label] = fmt.Sprintf("%+v", val)
   192  				routeReq.AddArguments(model.BuildArgumentFromLabel(label, fmt.Sprintf("%+v", val)))
   193  			}
   194  		}
   195  		if strings.HasPrefix(label, model.LabelKeyQuery) {
   196  			if val := parser.ParseArgumentsByExpression(label, arguments); val != nil {
   197  				routeReq.AddArguments(model.BuildArgumentFromLabel(label, fmt.Sprintf("%+v", val)))
   198  			}
   199  		}
   200  	}
   201  
   202  	return routeReq, nil
   203  }
   204  
   205  func (p *polarisRouter) buildTrafficLabels(svc string) ([]string, error) {
   206  	req := &model.GetServiceRuleRequest{}
   207  	req.Namespace = remotingpolaris.GetNamespace()
   208  	req.Service = svc
   209  	req.SetTimeout(time.Second)
   210  	engine := p.routerAPI.SDKContext().GetEngine()
   211  	resp, err := engine.SyncGetServiceRule(model.EventRouting, req)
   212  	if err != nil {
   213  		logger.Errorf("[Router][Polaris] ns:%s svc:%s get route rule fail : %+v", req.GetNamespace(), req.GetService(), err)
   214  		return nil, err
   215  	}
   216  
   217  	if resp == nil || resp.GetValue() == nil {
   218  		logger.Errorf("[Router][Polaris] ns:%s svc:%s get route rule empty", req.GetNamespace(), req.GetService())
   219  		return nil, ErrorPolarisServiceRouteRuleEmpty
   220  	}
   221  
   222  	routeRule := resp.GetValue().(*v1.Routing)
   223  	labels := make([]string, 0, 4)
   224  	labels = append(labels, collectRouteLabels(routeRule.GetInbounds())...)
   225  	labels = append(labels, collectRouteLabels(routeRule.GetInbounds())...)
   226  
   227  	return labels, nil
   228  }
   229  
   230  func getInvokeMethod(url *common.URL, invoaction protocol.Invocation) string {
   231  	applicationMode := false
   232  	for _, item := range config.GetRootConfig().Registries {
   233  		if item.Protocol == constant.PolarisKey {
   234  			applicationMode = item.RegistryType == constant.ServiceKey
   235  		}
   236  	}
   237  
   238  	method := invoaction.MethodName()
   239  	if applicationMode {
   240  		method = url.Interface() + "/" + invoaction.MethodName()
   241  	}
   242  
   243  	return method
   244  }
   245  
   246  func collectRouteLabels(routings []*v1.Route) []string {
   247  	ret := make([]string, 0, 4)
   248  
   249  	for i := range routings {
   250  		route := routings[i]
   251  		sources := route.GetSources()
   252  		for p := range sources {
   253  			source := sources[p]
   254  			for k := range source.GetMetadata() {
   255  				ret = append(ret, k)
   256  			}
   257  		}
   258  	}
   259  
   260  	return ret
   261  }
   262  
   263  func (p *polarisRouter) buildInstanceMap(svc string) map[string]model.Instance {
   264  	resp, err := p.consumerAPI.GetAllInstances(&polaris.GetAllInstancesRequest{
   265  		GetAllInstancesRequest: model.GetAllInstancesRequest{
   266  			Service:   svc,
   267  			Namespace: remotingpolaris.GetNamespace(),
   268  		},
   269  	})
   270  	if err != nil {
   271  		logger.Errorf("[Router][Polaris] ns:%s svc:%s get all instances fail : %+v", remotingpolaris.GetNamespace(), svc, err)
   272  		return nil
   273  	}
   274  
   275  	ret := make(map[string]model.Instance, len(resp.GetInstances()))
   276  
   277  	for i := range resp.GetInstances() {
   278  		ret[resp.GetInstances()[i].GetId()] = resp.GetInstances()[i]
   279  	}
   280  
   281  	return ret
   282  }
   283  
   284  // URL Return URL in router
   285  func (p *polarisRouter) URL() *common.URL {
   286  	return nil
   287  }
   288  
   289  // Priority Return Priority in router
   290  // 0 to ^int(0) is better
   291  func (p *polarisRouter) Priority() int64 {
   292  	return 0
   293  }
   294  
   295  // Notify the router the invoker list
   296  func (p *polarisRouter) Notify(invokers []protocol.Invoker) {
   297  	if !p.openRoute {
   298  		return
   299  	}
   300  	if len(invokers) == 0 {
   301  		return
   302  	}
   303  	service := getService(invokers[0].GetURL())
   304  	if service == "" {
   305  		logger.Error("url service is empty")
   306  		return
   307  	}
   308  
   309  	req := &model.GetServiceRuleRequest{}
   310  	req.Namespace = remotingpolaris.GetNamespace()
   311  	req.Service = service
   312  	req.SetTimeout(time.Second)
   313  
   314  	engine := p.routerAPI.SDKContext().GetEngine()
   315  	_, err := engine.SyncGetServiceRule(model.EventRouting, req)
   316  	if err != nil {
   317  		logger.Errorf("[Router][Polaris] ns:%s svc:%s get route rule fail : %+v", req.GetNamespace(), req.GetService(), err)
   318  		return
   319  	}
   320  
   321  	_, err = p.consumerAPI.GetAllInstances(&polaris.GetAllInstancesRequest{
   322  		GetAllInstancesRequest: model.GetAllInstancesRequest{
   323  			Service:   service,
   324  			Namespace: remotingpolaris.GetNamespace(),
   325  		},
   326  	})
   327  	if err != nil {
   328  		logger.Errorf("[Router][Polaris] ns:%s svc:%s get all instances fail : %+v", req.GetNamespace(), req.GetService(), err)
   329  		return
   330  	}
   331  }