trpc.group/trpc-go/trpc-go@v1.0.3/naming/selector/trpc_selector.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package selector
    15  
    16  import (
    17  	"errors"
    18  	"time"
    19  
    20  	"trpc.group/trpc-go/trpc-go/naming/circuitbreaker"
    21  	"trpc.group/trpc-go/trpc-go/naming/discovery"
    22  	"trpc.group/trpc-go/trpc-go/naming/loadbalance"
    23  	"trpc.group/trpc-go/trpc-go/naming/registry"
    24  	"trpc.group/trpc-go/trpc-go/naming/servicerouter"
    25  )
    26  
    27  // Errors when route failed.
    28  var (
    29  	ErrReportNodeEmpty             = errors.New("selector report node empty")
    30  	ErrReportMetaDataEmpty         = errors.New("selector report metadata empty")
    31  	ErrReportNoCircuitBreaker      = errors.New("selector report not circuitbreaker")
    32  	ErrReportInvalidCircuitBreaker = errors.New("selector report circuitbreaker invalid")
    33  )
    34  
    35  // DefaultSelector is the default Selector.
    36  var DefaultSelector Selector = &TrpcSelector{}
    37  
    38  // TrpcSelector is the default Selector implementation of tRPC. It automatically combines pluggable
    39  // modules, like, service discovery, load balance and circuit breaker.
    40  type TrpcSelector struct{}
    41  
    42  // Select returns an available node by service name.
    43  func (s *TrpcSelector) Select(serviceName string, opt ...Option) (*registry.Node, error) {
    44  	if serviceName == "" {
    45  		return nil, errors.New("service name empty")
    46  	}
    47  
    48  	opts := &Options{
    49  		Discovery:            discovery.DefaultDiscovery,
    50  		DiscoveryOptions:     make([]discovery.Option, 0, defaultDiscoveryOptionsSize),
    51  		LoadBalancer:         loadbalance.DefaultLoadBalancer,
    52  		LoadBalanceOptions:   make([]loadbalance.Option, 0, defaultLoadBalanceOptionsSize),
    53  		ServiceRouter:        servicerouter.DefaultServiceRouter,
    54  		ServiceRouterOptions: make([]servicerouter.Option, 0, defaultServiceRouterOptionsSize),
    55  		CircuitBreaker:       circuitbreaker.DefaultCircuitBreaker,
    56  	}
    57  	for _, o := range opt {
    58  		o(opts)
    59  	}
    60  
    61  	if opts.Discovery == nil {
    62  		return nil, errors.New("discovery not exists")
    63  	}
    64  	list, err := opts.Discovery.List(serviceName, opts.DiscoveryOptions...)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	if opts.ServiceRouter == nil {
    70  		return nil, errors.New("servicerouter not exists")
    71  	}
    72  	list, err = opts.ServiceRouter.Filter(serviceName, list, opts.ServiceRouterOptions...)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	if opts.LoadBalancer == nil {
    78  		return nil, errors.New("loadbalancer not exists")
    79  	}
    80  
    81  	if opts.CircuitBreaker == nil {
    82  		return nil, errors.New("circuitbreaker not exists")
    83  	}
    84  
    85  	node, err := opts.LoadBalancer.Select(serviceName, list, opts.LoadBalanceOptions...)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	if len(node.Metadata) == 0 {
    91  		node.Metadata = make(map[string]interface{})
    92  	}
    93  	node.Metadata["circuitbreaker"] = opts.CircuitBreaker
    94  	return node, nil
    95  }
    96  
    97  // Report reports result.
    98  func (s *TrpcSelector) Report(node *registry.Node, cost time.Duration, err error) error {
    99  	if node == nil {
   100  		return ErrReportNodeEmpty
   101  	}
   102  	if node.Metadata == nil {
   103  		return ErrReportMetaDataEmpty
   104  	}
   105  	breaker, ok := node.Metadata["circuitbreaker"]
   106  	if !ok {
   107  		return ErrReportNoCircuitBreaker
   108  	}
   109  	circuitbreaker, ok := breaker.(circuitbreaker.CircuitBreaker)
   110  	if !ok {
   111  		return ErrReportInvalidCircuitBreaker
   112  	}
   113  	return circuitbreaker.Report(node, cost, err)
   114  }