github.com/cloudwego/kitex@v0.9.0/internal/client/option.go (about)

     1  /*
     2   * Copyright 2021 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  // Package client defines the Options of client
    18  package client
    19  
    20  import (
    21  	"context"
    22  	"time"
    23  
    24  	"github.com/cloudwego/localsession/backup"
    25  
    26  	"github.com/cloudwego/kitex/internal/configutil"
    27  	"github.com/cloudwego/kitex/internal/stream"
    28  	"github.com/cloudwego/kitex/pkg/acl"
    29  	"github.com/cloudwego/kitex/pkg/circuitbreak"
    30  	connpool2 "github.com/cloudwego/kitex/pkg/connpool"
    31  	"github.com/cloudwego/kitex/pkg/diagnosis"
    32  	"github.com/cloudwego/kitex/pkg/discovery"
    33  	"github.com/cloudwego/kitex/pkg/endpoint"
    34  	"github.com/cloudwego/kitex/pkg/event"
    35  	"github.com/cloudwego/kitex/pkg/fallback"
    36  	"github.com/cloudwego/kitex/pkg/http"
    37  	"github.com/cloudwego/kitex/pkg/loadbalance"
    38  	"github.com/cloudwego/kitex/pkg/loadbalance/lbcache"
    39  	"github.com/cloudwego/kitex/pkg/proxy"
    40  	"github.com/cloudwego/kitex/pkg/remote"
    41  	"github.com/cloudwego/kitex/pkg/remote/codec/protobuf"
    42  	"github.com/cloudwego/kitex/pkg/remote/codec/thrift"
    43  	"github.com/cloudwego/kitex/pkg/remote/connpool"
    44  	"github.com/cloudwego/kitex/pkg/remote/trans/nphttp2"
    45  	"github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/grpc"
    46  	"github.com/cloudwego/kitex/pkg/retry"
    47  	"github.com/cloudwego/kitex/pkg/rpcinfo"
    48  	"github.com/cloudwego/kitex/pkg/serviceinfo"
    49  	"github.com/cloudwego/kitex/pkg/stats"
    50  	"github.com/cloudwego/kitex/pkg/transmeta"
    51  	"github.com/cloudwego/kitex/pkg/utils"
    52  	"github.com/cloudwego/kitex/pkg/warmup"
    53  	"github.com/cloudwego/kitex/transport"
    54  )
    55  
    56  func init() {
    57  	remote.PutPayloadCode(serviceinfo.Thrift, thrift.NewThriftCodec())
    58  	remote.PutPayloadCode(serviceinfo.Protobuf, protobuf.NewProtobufCodec())
    59  }
    60  
    61  // Options is used to initialize a client.
    62  type Options struct {
    63  	Cli     *rpcinfo.EndpointBasicInfo
    64  	Svr     *rpcinfo.EndpointBasicInfo
    65  	Configs rpcinfo.RPCConfig
    66  	Locks   *ConfigLocks
    67  	Once    *configutil.OptionOnce
    68  
    69  	MetaHandlers []remote.MetaHandler
    70  
    71  	RemoteOpt        *remote.ClientOption
    72  	Proxy            proxy.ForwardProxy
    73  	Resolver         discovery.Resolver
    74  	HTTPResolver     http.Resolver
    75  	Balancer         loadbalance.Loadbalancer
    76  	BalancerCacheOpt *lbcache.Options
    77  	PoolCfg          *connpool2.IdleConfig
    78  	ErrHandle        func(context.Context, error) error
    79  	Targets          string
    80  	CBSuite          *circuitbreak.CBSuite
    81  	Timeouts         rpcinfo.TimeoutProvider
    82  
    83  	ACLRules []acl.RejectFunc
    84  
    85  	MWBs  []endpoint.MiddlewareBuilder
    86  	IMWBs []endpoint.MiddlewareBuilder
    87  
    88  	Bus          event.Bus
    89  	Events       event.Queue
    90  	ExtraTimeout time.Duration
    91  
    92  	// DebugInfo should only contain objects that are suitable for json serialization.
    93  	DebugInfo    utils.Slice
    94  	DebugService diagnosis.Service
    95  
    96  	// Observability
    97  	TracerCtl  *rpcinfo.TraceController
    98  	StatsLevel *stats.Level
    99  
   100  	// retry policy
   101  	RetryMethodPolicies map[string]retry.Policy
   102  	RetryContainer      *retry.Container
   103  	RetryWithResult     *retry.ShouldResultRetry
   104  
   105  	// fallback policy
   106  	Fallback *fallback.Policy
   107  
   108  	CloseCallbacks []func() error
   109  	WarmUpOption   *warmup.ClientOption
   110  
   111  	// GRPC
   112  	GRPCConnPoolSize uint32
   113  	GRPCConnectOpts  *grpc.ConnectOptions
   114  
   115  	// XDS
   116  	XDSEnabled          bool
   117  	XDSRouterMiddleware endpoint.Middleware
   118  
   119  	// Context backup
   120  	CtxBackupHandler backup.BackupHandler
   121  
   122  	Streaming stream.StreamingConfig
   123  }
   124  
   125  // Apply applies all options.
   126  func (o *Options) Apply(opts []Option) {
   127  	for _, op := range opts {
   128  		op.F(o, &o.DebugInfo)
   129  	}
   130  }
   131  
   132  // Option is the only way to config client.
   133  type Option struct {
   134  	F func(o *Options, di *utils.Slice)
   135  }
   136  
   137  // NewOptions creates a new option.
   138  func NewOptions(opts []Option) *Options {
   139  	o := &Options{
   140  		Cli:          &rpcinfo.EndpointBasicInfo{Tags: make(map[string]string)},
   141  		Svr:          &rpcinfo.EndpointBasicInfo{Tags: make(map[string]string)},
   142  		MetaHandlers: []remote.MetaHandler{transmeta.MetainfoClientHandler},
   143  		RemoteOpt:    newClientRemoteOption(),
   144  		Configs:      rpcinfo.NewRPCConfig(),
   145  		Locks:        NewConfigLocks(),
   146  		Once:         configutil.NewOptionOnce(),
   147  		HTTPResolver: http.NewDefaultResolver(),
   148  		DebugService: diagnosis.NoopService,
   149  
   150  		Bus:    event.NewEventBus(),
   151  		Events: event.NewQueue(event.MaxEventNum),
   152  
   153  		TracerCtl: &rpcinfo.TraceController{},
   154  
   155  		GRPCConnectOpts: new(grpc.ConnectOptions),
   156  	}
   157  	o.Apply(opts)
   158  
   159  	o.initRemoteOpt()
   160  
   161  	if o.RetryContainer != nil && o.DebugService != nil {
   162  		o.DebugService.RegisterProbeFunc(diagnosis.RetryPolicyKey, o.RetryContainer.Dump)
   163  	}
   164  
   165  	if o.StatsLevel == nil {
   166  		level := stats.LevelDisabled
   167  		if o.TracerCtl.HasTracer() {
   168  			level = stats.LevelDetailed
   169  		}
   170  		o.StatsLevel = &level
   171  	}
   172  	return o
   173  }
   174  
   175  func (o *Options) initRemoteOpt() {
   176  	var zero connpool2.IdleConfig
   177  
   178  	if o.Configs.TransportProtocol()&transport.GRPC == transport.GRPC {
   179  		if o.PoolCfg != nil && *o.PoolCfg == zero {
   180  			// grpc unary short connection
   181  			o.GRPCConnectOpts.ShortConn = true
   182  		}
   183  		o.RemoteOpt.ConnPool = nphttp2.NewConnPool(o.Svr.ServiceName, o.GRPCConnPoolSize, *o.GRPCConnectOpts)
   184  		o.RemoteOpt.CliHandlerFactory = nphttp2.NewCliTransHandlerFactory()
   185  	}
   186  	if o.RemoteOpt.ConnPool == nil {
   187  		if o.PoolCfg != nil {
   188  			if *o.PoolCfg == zero {
   189  				o.RemoteOpt.ConnPool = connpool.NewShortPool(o.Svr.ServiceName)
   190  			} else {
   191  				o.RemoteOpt.ConnPool = connpool.NewLongPool(o.Svr.ServiceName, *o.PoolCfg)
   192  			}
   193  		} else {
   194  			o.RemoteOpt.ConnPool = connpool.NewLongPool(
   195  				o.Svr.ServiceName,
   196  				connpool2.IdleConfig{
   197  					MaxIdlePerAddress: 10,
   198  					MaxIdleGlobal:     100,
   199  					MaxIdleTimeout:    time.Minute,
   200  				},
   201  			)
   202  		}
   203  	}
   204  }
   205  
   206  // InitRetryContainer init retry container and add close callback
   207  func (o *Options) InitRetryContainer() {
   208  	if o.RetryContainer == nil {
   209  		o.RetryContainer = retry.NewRetryContainerWithPercentageLimit()
   210  		o.CloseCallbacks = append(o.CloseCallbacks, o.RetryContainer.Close)
   211  	}
   212  }