github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/dialoptions.go (about) 1 /* 2 * 3 * Copyright 2018 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * 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 19 package grpc 20 21 import ( 22 "context" 23 "fmt" 24 "net" 25 "time" 26 27 "github.com/hxx258456/ccgo/grpc/backoff" 28 "github.com/hxx258456/ccgo/grpc/balancer" 29 "github.com/hxx258456/ccgo/grpc/credentials" 30 "github.com/hxx258456/ccgo/grpc/credentials/insecure" 31 "github.com/hxx258456/ccgo/grpc/internal" 32 internalbackoff "github.com/hxx258456/ccgo/grpc/internal/backoff" 33 "github.com/hxx258456/ccgo/grpc/internal/transport" 34 "github.com/hxx258456/ccgo/grpc/keepalive" 35 "github.com/hxx258456/ccgo/grpc/resolver" 36 "github.com/hxx258456/ccgo/grpc/stats" 37 ) 38 39 // dialOptions configure a Dial call. dialOptions are set by the DialOption 40 // values passed to Dial. 41 type dialOptions struct { 42 unaryInt UnaryClientInterceptor 43 streamInt StreamClientInterceptor 44 45 chainUnaryInts []UnaryClientInterceptor 46 chainStreamInts []StreamClientInterceptor 47 48 cp Compressor 49 dc Decompressor 50 bs internalbackoff.Strategy 51 block bool 52 returnLastError bool 53 timeout time.Duration 54 scChan <-chan ServiceConfig 55 authority string 56 copts transport.ConnectOptions 57 callOptions []CallOption 58 // This is used by WithBalancerName dial option. 59 balancerBuilder balancer.Builder 60 channelzParentID int64 61 disableServiceConfig bool 62 disableRetry bool 63 disableHealthCheck bool 64 healthCheckFunc internal.HealthChecker 65 minConnectTimeout func() time.Duration 66 defaultServiceConfig *ServiceConfig // defaultServiceConfig is parsed from defaultServiceConfigRawJSON. 67 defaultServiceConfigRawJSON *string 68 resolvers []resolver.Builder 69 } 70 71 // DialOption configures how we set up the connection. 72 type DialOption interface { 73 apply(*dialOptions) 74 } 75 76 // EmptyDialOption does not alter the dial configuration. It can be embedded in 77 // another structure to build custom dial options. 78 // 79 // Experimental 80 // 81 // Notice: This type is EXPERIMENTAL and may be changed or removed in a 82 // later release. 83 type EmptyDialOption struct{} 84 85 func (EmptyDialOption) apply(*dialOptions) {} 86 87 // funcDialOption wraps a function that modifies dialOptions into an 88 // implementation of the DialOption interface. 89 type funcDialOption struct { 90 f func(*dialOptions) 91 } 92 93 func (fdo *funcDialOption) apply(do *dialOptions) { 94 fdo.f(do) 95 } 96 97 func newFuncDialOption(f func(*dialOptions)) *funcDialOption { 98 return &funcDialOption{ 99 f: f, 100 } 101 } 102 103 // WithWriteBufferSize determines how much data can be batched before doing a 104 // write on the wire. The corresponding memory allocation for this buffer will 105 // be twice the size to keep syscalls low. The default value for this buffer is 106 // 32KB. 107 // 108 // Zero will disable the write buffer such that each write will be on underlying 109 // connection. Note: A Send call may not directly translate to a write. 110 func WithWriteBufferSize(s int) DialOption { 111 return newFuncDialOption(func(o *dialOptions) { 112 o.copts.WriteBufferSize = s 113 }) 114 } 115 116 // WithReadBufferSize lets you set the size of read buffer, this determines how 117 // much data can be read at most for each read syscall. 118 // 119 // The default value for this buffer is 32KB. Zero will disable read buffer for 120 // a connection so data framer can access the underlying conn directly. 121 func WithReadBufferSize(s int) DialOption { 122 return newFuncDialOption(func(o *dialOptions) { 123 o.copts.ReadBufferSize = s 124 }) 125 } 126 127 // WithInitialWindowSize returns a DialOption which sets the value for initial 128 // window size on a stream. The lower bound for window size is 64K and any value 129 // smaller than that will be ignored. 130 func WithInitialWindowSize(s int32) DialOption { 131 return newFuncDialOption(func(o *dialOptions) { 132 o.copts.InitialWindowSize = s 133 }) 134 } 135 136 // WithInitialConnWindowSize returns a DialOption which sets the value for 137 // initial window size on a connection. The lower bound for window size is 64K 138 // and any value smaller than that will be ignored. 139 func WithInitialConnWindowSize(s int32) DialOption { 140 return newFuncDialOption(func(o *dialOptions) { 141 o.copts.InitialConnWindowSize = s 142 }) 143 } 144 145 // WithMaxMsgSize returns a DialOption which sets the maximum message size the 146 // client can receive. 147 // 148 // Deprecated: use WithDefaultCallOptions(MaxCallRecvMsgSize(s)) instead. Will 149 // be supported throughout 1.x. 150 func WithMaxMsgSize(s int) DialOption { 151 return WithDefaultCallOptions(MaxCallRecvMsgSize(s)) 152 } 153 154 // WithDefaultCallOptions returns a DialOption which sets the default 155 // CallOptions for calls over the connection. 156 func WithDefaultCallOptions(cos ...CallOption) DialOption { 157 return newFuncDialOption(func(o *dialOptions) { 158 o.callOptions = append(o.callOptions, cos...) 159 }) 160 } 161 162 // WithCodec returns a DialOption which sets a codec for message marshaling and 163 // unmarshaling. 164 // 165 // Deprecated: use WithDefaultCallOptions(ForceCodec(_)) instead. Will be 166 // supported throughout 1.x. 167 func WithCodec(c Codec) DialOption { 168 return WithDefaultCallOptions(CallCustomCodec(c)) 169 } 170 171 // WithCompressor returns a DialOption which sets a Compressor to use for 172 // message compression. It has lower priority than the compressor set by the 173 // UseCompressor CallOption. 174 // 175 // Deprecated: use UseCompressor instead. Will be supported throughout 1.x. 176 func WithCompressor(cp Compressor) DialOption { 177 return newFuncDialOption(func(o *dialOptions) { 178 o.cp = cp 179 }) 180 } 181 182 // WithDecompressor returns a DialOption which sets a Decompressor to use for 183 // incoming message decompression. If incoming response messages are encoded 184 // using the decompressor's Type(), it will be used. Otherwise, the message 185 // encoding will be used to look up the compressor registered via 186 // encoding.RegisterCompressor, which will then be used to decompress the 187 // message. If no compressor is registered for the encoding, an Unimplemented 188 // status error will be returned. 189 // 190 // Deprecated: use encoding.RegisterCompressor instead. Will be supported 191 // throughout 1.x. 192 func WithDecompressor(dc Decompressor) DialOption { 193 return newFuncDialOption(func(o *dialOptions) { 194 o.dc = dc 195 }) 196 } 197 198 // WithBalancerName sets the balancer that the ClientConn will be initialized 199 // with. Balancer registered with balancerName will be used. This function 200 // panics if no balancer was registered by balancerName. 201 // 202 // The balancer cannot be overridden by balancer option specified by service 203 // config. 204 // 205 // Deprecated: use WithDefaultServiceConfig and WithDisableServiceConfig 206 // instead. Will be removed in a future 1.x release. 207 func WithBalancerName(balancerName string) DialOption { 208 builder := balancer.Get(balancerName) 209 if builder == nil { 210 panic(fmt.Sprintf("grpc.WithBalancerName: no balancer is registered for name %v", balancerName)) 211 } 212 return newFuncDialOption(func(o *dialOptions) { 213 o.balancerBuilder = builder 214 }) 215 } 216 217 // WithServiceConfig returns a DialOption which has a channel to read the 218 // service configuration. 219 // 220 // Deprecated: service config should be received through name resolver or via 221 // WithDefaultServiceConfig, as specified at 222 // https://github.com/grpc/grpc/blob/master/doc/service_config.md. Will be 223 // removed in a future 1.x release. 224 func WithServiceConfig(c <-chan ServiceConfig) DialOption { 225 return newFuncDialOption(func(o *dialOptions) { 226 o.scChan = c 227 }) 228 } 229 230 // WithConnectParams configures the ClientConn to use the provided ConnectParams 231 // for creating and maintaining connections to servers. 232 // 233 // The backoff configuration specified as part of the ConnectParams overrides 234 // all defaults specified in 235 // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Consider 236 // using the backoff.DefaultConfig as a base, in cases where you want to 237 // override only a subset of the backoff configuration. 238 func WithConnectParams(p ConnectParams) DialOption { 239 return newFuncDialOption(func(o *dialOptions) { 240 o.bs = internalbackoff.Exponential{Config: p.Backoff} 241 o.minConnectTimeout = func() time.Duration { 242 return p.MinConnectTimeout 243 } 244 }) 245 } 246 247 // WithBackoffMaxDelay configures the dialer to use the provided maximum delay 248 // when backing off after failed connection attempts. 249 // 250 // Deprecated: use WithConnectParams instead. Will be supported throughout 1.x. 251 func WithBackoffMaxDelay(md time.Duration) DialOption { 252 return WithBackoffConfig(BackoffConfig{MaxDelay: md}) 253 } 254 255 // WithBackoffConfig configures the dialer to use the provided backoff 256 // parameters after connection failures. 257 // 258 // Deprecated: use WithConnectParams instead. Will be supported throughout 1.x. 259 func WithBackoffConfig(b BackoffConfig) DialOption { 260 bc := backoff.DefaultConfig 261 bc.MaxDelay = b.MaxDelay 262 return withBackoff(internalbackoff.Exponential{Config: bc}) 263 } 264 265 // withBackoff sets the backoff strategy used for connectRetryNum after a failed 266 // connection attempt. 267 // 268 // This can be exported if arbitrary backoff strategies are allowed by gRPC. 269 func withBackoff(bs internalbackoff.Strategy) DialOption { 270 return newFuncDialOption(func(o *dialOptions) { 271 o.bs = bs 272 }) 273 } 274 275 // WithBlock returns a DialOption which makes callers of Dial block until the 276 // underlying connection is up. Without this, Dial returns immediately and 277 // connecting the server happens in background. 278 func WithBlock() DialOption { 279 return newFuncDialOption(func(o *dialOptions) { 280 o.block = true 281 }) 282 } 283 284 // WithReturnConnectionError returns a DialOption which makes the client connection 285 // return a string containing both the last connection error that occurred and 286 // the context.DeadlineExceeded error. 287 // Implies WithBlock() 288 // 289 // Experimental 290 // 291 // Notice: This API is EXPERIMENTAL and may be changed or removed in a 292 // later release. 293 func WithReturnConnectionError() DialOption { 294 return newFuncDialOption(func(o *dialOptions) { 295 o.block = true 296 o.returnLastError = true 297 }) 298 } 299 300 // WithInsecure returns a DialOption which disables transport security for this 301 // ClientConn. Under the hood, it uses insecure.NewCredentials(). 302 // 303 // Note that using this DialOption with per-RPC credentials (through 304 // WithCredentialsBundle or WithPerRPCCredentials) which require transport 305 // security is incompatible and will cause grpc.Dial() to fail. 306 // 307 // Deprecated: use WithTransportCredentials and insecure.NewCredentials() instead. 308 // Will be supported throughout 1.x. 309 func WithInsecure() DialOption { 310 return newFuncDialOption(func(o *dialOptions) { 311 o.copts.TransportCredentials = insecure.NewCredentials() 312 }) 313 } 314 315 // WithNoProxy returns a DialOption which disables the use of proxies for this 316 // ClientConn. This is ignored if WithDialer or WithContextDialer are used. 317 // 318 // Experimental 319 // 320 // Notice: This API is EXPERIMENTAL and may be changed or removed in a 321 // later release. 322 func WithNoProxy() DialOption { 323 return newFuncDialOption(func(o *dialOptions) { 324 o.copts.UseProxy = false 325 }) 326 } 327 328 // WithTransportCredentials returns a DialOption which configures a connection 329 // level security credentials (e.g., TLS/SSL). This should not be used together 330 // with WithCredentialsBundle. 331 func WithTransportCredentials(creds credentials.TransportCredentials) DialOption { 332 return newFuncDialOption(func(o *dialOptions) { 333 o.copts.TransportCredentials = creds 334 }) 335 } 336 337 // WithPerRPCCredentials returns a DialOption which sets credentials and places 338 // auth state on each outbound RPC. 339 func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption { 340 return newFuncDialOption(func(o *dialOptions) { 341 o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds) 342 }) 343 } 344 345 // WithCredentialsBundle returns a DialOption to set a credentials bundle for 346 // the ClientConn.WithCreds. This should not be used together with 347 // WithTransportCredentials. 348 // 349 // Experimental 350 // 351 // Notice: This API is EXPERIMENTAL and may be changed or removed in a 352 // later release. 353 func WithCredentialsBundle(b credentials.Bundle) DialOption { 354 return newFuncDialOption(func(o *dialOptions) { 355 o.copts.CredsBundle = b 356 }) 357 } 358 359 // WithTimeout returns a DialOption that configures a timeout for dialing a 360 // ClientConn initially. This is valid if and only if WithBlock() is present. 361 // 362 // Deprecated: use DialContext instead of Dial and context.WithTimeout 363 // instead. Will be supported throughout 1.x. 364 func WithTimeout(d time.Duration) DialOption { 365 return newFuncDialOption(func(o *dialOptions) { 366 o.timeout = d 367 }) 368 } 369 370 // WithContextDialer returns a DialOption that sets a dialer to create 371 // connections. If FailOnNonTempDialError() is set to true, and an error is 372 // returned by f, gRPC checks the error's Temporary() method to decide if it 373 // should try to reconnect to the network address. 374 func WithContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption { 375 return newFuncDialOption(func(o *dialOptions) { 376 o.copts.Dialer = f 377 }) 378 } 379 380 func init() { 381 internal.WithHealthCheckFunc = withHealthCheckFunc 382 } 383 384 // WithDialer returns a DialOption that specifies a function to use for dialing 385 // network addresses. If FailOnNonTempDialError() is set to true, and an error 386 // is returned by f, gRPC checks the error's Temporary() method to decide if it 387 // should try to reconnect to the network address. 388 // 389 // Deprecated: use WithContextDialer instead. Will be supported throughout 390 // 1.x. 391 func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption { 392 return WithContextDialer( 393 func(ctx context.Context, addr string) (net.Conn, error) { 394 if deadline, ok := ctx.Deadline(); ok { 395 return f(addr, time.Until(deadline)) 396 } 397 return f(addr, 0) 398 }) 399 } 400 401 // WithStatsHandler returns a DialOption that specifies the stats handler for 402 // all the RPCs and underlying network connections in this ClientConn. 403 func WithStatsHandler(h stats.Handler) DialOption { 404 return newFuncDialOption(func(o *dialOptions) { 405 o.copts.StatsHandler = h 406 }) 407 } 408 409 // FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on 410 // non-temporary dial errors. If f is true, and dialer returns a non-temporary 411 // error, gRPC will fail the connection to the network address and won't try to 412 // reconnect. The default value of FailOnNonTempDialError is false. 413 // 414 // FailOnNonTempDialError only affects the initial dial, and does not do 415 // anything useful unless you are also using WithBlock(). 416 // 417 // Experimental 418 // 419 // Notice: This API is EXPERIMENTAL and may be changed or removed in a 420 // later release. 421 func FailOnNonTempDialError(f bool) DialOption { 422 return newFuncDialOption(func(o *dialOptions) { 423 o.copts.FailOnNonTempDialError = f 424 }) 425 } 426 427 // WithUserAgent returns a DialOption that specifies a user agent string for all 428 // the RPCs. 429 func WithUserAgent(s string) DialOption { 430 return newFuncDialOption(func(o *dialOptions) { 431 o.copts.UserAgent = s 432 }) 433 } 434 435 // WithKeepaliveParams returns a DialOption that specifies keepalive parameters 436 // for the client transport. 437 func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption { 438 if kp.Time < internal.KeepaliveMinPingTime { 439 logger.Warningf("Adjusting keepalive ping interval to minimum period of %v", internal.KeepaliveMinPingTime) 440 kp.Time = internal.KeepaliveMinPingTime 441 } 442 return newFuncDialOption(func(o *dialOptions) { 443 o.copts.KeepaliveParams = kp 444 }) 445 } 446 447 // WithUnaryInterceptor returns a DialOption that specifies the interceptor for 448 // unary RPCs. 449 func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption { 450 return newFuncDialOption(func(o *dialOptions) { 451 o.unaryInt = f 452 }) 453 } 454 455 // WithChainUnaryInterceptor returns a DialOption that specifies the chained 456 // interceptor for unary RPCs. The first interceptor will be the outer most, 457 // while the last interceptor will be the inner most wrapper around the real call. 458 // All interceptors added by this method will be chained, and the interceptor 459 // defined by WithUnaryInterceptor will always be prepended to the chain. 460 func WithChainUnaryInterceptor(interceptors ...UnaryClientInterceptor) DialOption { 461 return newFuncDialOption(func(o *dialOptions) { 462 o.chainUnaryInts = append(o.chainUnaryInts, interceptors...) 463 }) 464 } 465 466 // WithStreamInterceptor returns a DialOption that specifies the interceptor for 467 // streaming RPCs. 468 func WithStreamInterceptor(f StreamClientInterceptor) DialOption { 469 return newFuncDialOption(func(o *dialOptions) { 470 o.streamInt = f 471 }) 472 } 473 474 // WithChainStreamInterceptor returns a DialOption that specifies the chained 475 // interceptor for streaming RPCs. The first interceptor will be the outer most, 476 // while the last interceptor will be the inner most wrapper around the real call. 477 // All interceptors added by this method will be chained, and the interceptor 478 // defined by WithStreamInterceptor will always be prepended to the chain. 479 func WithChainStreamInterceptor(interceptors ...StreamClientInterceptor) DialOption { 480 return newFuncDialOption(func(o *dialOptions) { 481 o.chainStreamInts = append(o.chainStreamInts, interceptors...) 482 }) 483 } 484 485 // WithAuthority returns a DialOption that specifies the value to be used as the 486 // :authority pseudo-header and as the server name in authentication handshake. 487 func WithAuthority(a string) DialOption { 488 return newFuncDialOption(func(o *dialOptions) { 489 o.authority = a 490 }) 491 } 492 493 // WithChannelzParentID returns a DialOption that specifies the channelz ID of 494 // current ClientConn's parent. This function is used in nested channel creation 495 // (e.g. grpclb dial). 496 // 497 // Experimental 498 // 499 // Notice: This API is EXPERIMENTAL and may be changed or removed in a 500 // later release. 501 func WithChannelzParentID(id int64) DialOption { 502 return newFuncDialOption(func(o *dialOptions) { 503 o.channelzParentID = id 504 }) 505 } 506 507 // WithDisableServiceConfig returns a DialOption that causes gRPC to ignore any 508 // service config provided by the resolver and provides a hint to the resolver 509 // to not fetch service configs. 510 // 511 // Note that this dial option only disables service config from resolver. If 512 // default service config is provided, gRPC will use the default service config. 513 func WithDisableServiceConfig() DialOption { 514 return newFuncDialOption(func(o *dialOptions) { 515 o.disableServiceConfig = true 516 }) 517 } 518 519 // WithDefaultServiceConfig returns a DialOption that configures the default 520 // service config, which will be used in cases where: 521 // 522 // 1. WithDisableServiceConfig is also used, or 523 // 524 // 2. The name resolver does not provide a service config or provides an 525 // invalid service config. 526 // 527 // The parameter s is the JSON representation of the default service config. 528 // For more information about service configs, see: 529 // https://github.com/grpc/grpc/blob/master/doc/service_config.md 530 // For a simple example of usage, see: 531 // examples/features/load_balancing/client/main.go 532 func WithDefaultServiceConfig(s string) DialOption { 533 return newFuncDialOption(func(o *dialOptions) { 534 o.defaultServiceConfigRawJSON = &s 535 }) 536 } 537 538 // WithDisableRetry returns a DialOption that disables retries, even if the 539 // service config enables them. This does not impact transparent retries, which 540 // will happen automatically if no data is written to the wire or if the RPC is 541 // unprocessed by the remote server. 542 // 543 // Retry support is currently enabled by default, but may be disabled by 544 // setting the environment variable "GRPC_GO_RETRY" to "off". 545 func WithDisableRetry() DialOption { 546 return newFuncDialOption(func(o *dialOptions) { 547 o.disableRetry = true 548 }) 549 } 550 551 // WithMaxHeaderListSize returns a DialOption that specifies the maximum 552 // (uncompressed) size of header list that the client is prepared to accept. 553 func WithMaxHeaderListSize(s uint32) DialOption { 554 return newFuncDialOption(func(o *dialOptions) { 555 o.copts.MaxHeaderListSize = &s 556 }) 557 } 558 559 // WithDisableHealthCheck disables the LB channel health checking for all 560 // SubConns of this ClientConn. 561 // 562 // Experimental 563 // 564 // Notice: This API is EXPERIMENTAL and may be changed or removed in a 565 // later release. 566 func WithDisableHealthCheck() DialOption { 567 return newFuncDialOption(func(o *dialOptions) { 568 o.disableHealthCheck = true 569 }) 570 } 571 572 // withHealthCheckFunc replaces the default health check function with the 573 // provided one. It makes tests easier to change the health check function. 574 // 575 // For testing purpose only. 576 func withHealthCheckFunc(f internal.HealthChecker) DialOption { 577 return newFuncDialOption(func(o *dialOptions) { 578 o.healthCheckFunc = f 579 }) 580 } 581 582 func defaultDialOptions() dialOptions { 583 return dialOptions{ 584 healthCheckFunc: internal.HealthCheckFunc, 585 copts: transport.ConnectOptions{ 586 WriteBufferSize: defaultWriteBufSize, 587 ReadBufferSize: defaultReadBufSize, 588 UseProxy: true, 589 }, 590 } 591 } 592 593 // withGetMinConnectDeadline specifies the function that clientconn uses to 594 // get minConnectDeadline. This can be used to make connection attempts happen 595 // faster/slower. 596 // 597 // For testing purpose only. 598 func withMinConnectDeadline(f func() time.Duration) DialOption { 599 return newFuncDialOption(func(o *dialOptions) { 600 o.minConnectTimeout = f 601 }) 602 } 603 604 // WithResolvers allows a list of resolver implementations to be registered 605 // locally with the ClientConn without needing to be globally registered via 606 // resolver.Register. They will be matched against the scheme used for the 607 // current Dial only, and will take precedence over the global registry. 608 // 609 // Experimental 610 // 611 // Notice: This API is EXPERIMENTAL and may be changed or removed in a 612 // later release. 613 func WithResolvers(rs ...resolver.Builder) DialOption { 614 return newFuncDialOption(func(o *dialOptions) { 615 o.resolvers = append(o.resolvers, rs...) 616 }) 617 }