dialoptions.go 21 KB

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