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 }