• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

temporalio / sdk-java / #343

31 Oct 2024 06:31PM UTC coverage: 75.148% (-3.6%) from 78.794%
#343

push

github

web-flow
Fix jacoco coverage (#2304)

5139 of 8240 branches covered (62.37%)

Branch coverage included in aggregate %.

22841 of 28993 relevant lines covered (78.78%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.82
/temporal-serviceclient/src/main/java/io/temporal/serviceclient/ServiceStubsOptions.java
1
/*
2
 * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3
 *
4
 * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
 *
6
 * Modifications copyright (C) 2017 Uber Technologies, Inc.
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this material except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *   http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20

21
package io.temporal.serviceclient;
22

23
import com.google.common.base.MoreObjects;
24
import com.uber.m3.tally.NoopScope;
25
import com.uber.m3.tally.Scope;
26
import io.grpc.*;
27
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext;
28
import io.temporal.authorization.AuthorizationGrpcMetadataProvider;
29
import io.temporal.authorization.AuthorizationTokenSupplier;
30
import java.time.Duration;
31
import java.util.ArrayList;
32
import java.util.Collection;
33
import java.util.Collections;
34
import java.util.Objects;
35
import java.util.function.Consumer;
36
import javax.annotation.Nonnull;
37
import javax.annotation.Nullable;
38

39
public class ServiceStubsOptions {
40
  public static final String DEFAULT_LOCAL_DOCKER_TARGET = "127.0.0.1:7233";
41

42
  /** Default RPC timeout used for all non-long-poll and non-query calls. */
43
  public static final Duration DEFAULT_RPC_TIMEOUT = Duration.ofSeconds(10);
1✔
44

45
  /** Default timeout that will be used to reset connection backoff. */
46
  public static final Duration DEFAULT_CONNECTION_BACKOFF_RESET_FREQUENCY = Duration.ofSeconds(10);
1✔
47

48
  /**
49
   * Default timeout that will be used to enter idle channel state and reconnect to temporal server.
50
   */
51
  public static final Duration DEFAULT_GRPC_RECONNECT_FREQUENCY = Duration.ofMinutes(1);
1✔
52

53
  protected final ManagedChannel channel;
54

55
  /**
56
   * target string to use for connection/channel in {@link ManagedChannelBuilder#forTarget(String)}
57
   */
58
  protected final String target;
59

60
  protected final @Nullable Consumer<ManagedChannelBuilder<?>> channelInitializer;
61

62
  /** Indicates whether basic HTTPS/SSL/TLS should be enabled * */
63
  protected final boolean enableHttps;
64

65
  /** The user provided context for SSL/TLS over gRPC * */
66
  protected final SslContext sslContext;
67

68
  /**
69
   * HealthCheckAttemptTimeout specifies how to long to wait for service response on each health
70
   * check attempt. Default: 5s.
71
   */
72
  protected final Duration healthCheckAttemptTimeout;
73

74
  /**
75
   * SystemInfoTimeout specifies how to long to wait for service response on each health check
76
   * attempt. Default: 5s.
77
   */
78
  protected final Duration systemInfoTimeout;
79

80
  /**
81
   * HealthCheckTimeout defines how long client should be sending health check requests to the
82
   * server before concluding that it is unavailable. Defaults to 10s.
83
   */
84
  protected final Duration healthCheckTimeout;
85

86
  /**
87
   * Enables keep alive ping from client to the server, which can help drop abruptly closed
88
   * connections faster.
89
   */
90
  protected final boolean enableKeepAlive;
91

92
  /**
93
   * Interval at which server will be pinged in order to determine if connections are still alive.
94
   */
95
  protected final Duration keepAliveTime;
96

97
  /**
98
   * Amount of time that client would wait for the keep alive ping response from the server before
99
   * closing the connection.
100
   */
101
  protected final Duration keepAliveTimeout;
102

103
  /** If true, keep alive ping will be allowed when there are no active RPCs. */
104
  protected final boolean keepAlivePermitWithoutStream;
105

106
  /** The gRPC timeout */
107
  protected final Duration rpcTimeout;
108

109
  /** Frequency at which connection backoff is going to be reset */
110
  protected final Duration connectionBackoffResetFrequency;
111

112
  /**
113
   * Frequency at which grpc connection channel will be moved into an idle state, triggering a new
114
   * connection to the temporal frontend host.
115
   */
116
  protected final Duration grpcReconnectFrequency;
117

118
  /** Optional gRPC headers */
119
  protected final Metadata headers;
120

121
  /**
122
   * gRPC metadata/headers providers to be called on each gRPC request to supply additional headers
123
   */
124
  protected final Collection<GrpcMetadataProvider> grpcMetadataProviders;
125

126
  /** gRPC client interceptors to be added to gRPC channel */
127
  protected final Collection<ClientInterceptor> grpcClientInterceptors;
128

129
  protected final Scope metricsScope;
130

131
  ServiceStubsOptions(ServiceStubsOptions that) {
1✔
132
    this.channel = that.channel;
1✔
133
    this.target = that.target;
1✔
134
    this.channelInitializer = that.channelInitializer;
1✔
135
    this.enableHttps = that.enableHttps;
1✔
136
    this.sslContext = that.sslContext;
1✔
137
    this.healthCheckAttemptTimeout = that.healthCheckAttemptTimeout;
1✔
138
    this.systemInfoTimeout = that.systemInfoTimeout;
1✔
139
    this.healthCheckTimeout = that.healthCheckTimeout;
1✔
140
    this.enableKeepAlive = that.enableKeepAlive;
1✔
141
    this.keepAliveTime = that.keepAliveTime;
1✔
142
    this.keepAliveTimeout = that.keepAliveTimeout;
1✔
143
    this.keepAlivePermitWithoutStream = that.keepAlivePermitWithoutStream;
1✔
144
    this.rpcTimeout = that.rpcTimeout;
1✔
145
    this.connectionBackoffResetFrequency = that.connectionBackoffResetFrequency;
1✔
146
    this.grpcReconnectFrequency = that.grpcReconnectFrequency;
1✔
147
    this.headers = that.headers;
1✔
148
    this.grpcMetadataProviders = that.grpcMetadataProviders;
1✔
149
    this.grpcClientInterceptors = that.grpcClientInterceptors;
1✔
150
    this.metricsScope = that.metricsScope;
1✔
151
  }
1✔
152

153
  ServiceStubsOptions(
154
      ManagedChannel channel,
155
      String target,
156
      @Nullable Consumer<ManagedChannelBuilder<?>> channelInitializer,
157
      boolean enableHttps,
158
      SslContext sslContext,
159
      Duration healthCheckAttemptTimeout,
160
      Duration healthCheckTimeout,
161
      Duration systemInfoTimeout,
162
      boolean enableKeepAlive,
163
      Duration keepAliveTime,
164
      Duration keepAliveTimeout,
165
      boolean keepAlivePermitWithoutStream,
166
      Duration rpcTimeout,
167
      Duration connectionBackoffResetFrequency,
168
      Duration grpcReconnectFrequency,
169
      Metadata headers,
170
      Collection<GrpcMetadataProvider> grpcMetadataProviders,
171
      Collection<ClientInterceptor> grpcClientInterceptors,
172
      Scope metricsScope) {
1✔
173
    this.channel = channel;
1✔
174
    this.target = target;
1✔
175
    this.channelInitializer = channelInitializer;
1✔
176
    this.enableHttps = enableHttps;
1✔
177
    this.sslContext = sslContext;
1✔
178
    this.healthCheckAttemptTimeout = healthCheckAttemptTimeout;
1✔
179
    this.healthCheckTimeout = healthCheckTimeout;
1✔
180
    this.systemInfoTimeout = systemInfoTimeout;
1✔
181
    this.enableKeepAlive = enableKeepAlive;
1✔
182
    this.keepAliveTime = keepAliveTime;
1✔
183
    this.keepAliveTimeout = keepAliveTimeout;
1✔
184
    this.keepAlivePermitWithoutStream = keepAlivePermitWithoutStream;
1✔
185
    this.rpcTimeout = rpcTimeout;
1✔
186
    this.connectionBackoffResetFrequency = connectionBackoffResetFrequency;
1✔
187
    this.grpcReconnectFrequency = grpcReconnectFrequency;
1✔
188
    this.headers = headers;
1✔
189
    this.grpcMetadataProviders = grpcMetadataProviders;
1✔
190
    this.grpcClientInterceptors = grpcClientInterceptors;
1✔
191
    this.metricsScope = metricsScope;
1✔
192
  }
1✔
193

194
  /**
195
   * @return fully custom user-configured externally provided gRPC channel to use
196
   * @see Builder#setChannel(ManagedChannel)
197
   */
198
  public ManagedChannel getChannel() {
199
    return channel;
1✔
200
  }
201

202
  /**
203
   * @return the target string to use for connection/channel in {@link
204
   *     ManagedChannelBuilder#forTarget(String)}
205
   */
206
  public String getTarget() {
207
    return target;
1✔
208
  }
209

210
  /**
211
   * Gives an opportunity to provide some additional configuration to the channel builder or
212
   * override configurations done by the Temporal Stubs.
213
   *
214
   * <p>Advanced API
215
   *
216
   * @return listener that will be called as a last step of channel creation if the channel is
217
   *     configured by {@link Builder#setTarget(String)}.
218
   */
219
  @Nullable
220
  public Consumer<ManagedChannelBuilder<?>> getChannelInitializer() {
221
    return channelInitializer;
1✔
222
  }
223

224
  /**
225
   * @return if gRPC should use SSL/TLS; Ignored and assumed {@code true} if {@link
226
   *     #getSslContext()} is set
227
   */
228
  public boolean getEnableHttps() {
229
    return enableHttps;
1✔
230
  }
231

232
  /**
233
   * @return the gRPC SSL Context to use
234
   */
235
  public SslContext getSslContext() {
236
    return sslContext;
1✔
237
  }
238

239
  /**
240
   * @return how to long to wait for service response on each health check attempt
241
   */
242
  public Duration getHealthCheckAttemptTimeout() {
243
    return healthCheckAttemptTimeout;
1✔
244
  }
245

246
  /**
247
   * @return The timeout for the RPC made by the client to fetch server capabilities.
248
   */
249
  public Duration getSystemInfoTimeout() {
250
    return systemInfoTimeout;
1✔
251
  }
252

253
  /**
254
   * @return duration of time to wait while checking server connection when creating new client
255
   */
256
  public Duration getHealthCheckTimeout() {
257
    return healthCheckTimeout;
×
258
  }
259

260
  /**
261
   * @return true if ping from client to the server is enabled, which can help detect and drop
262
   *     abruptly closed connections faster
263
   */
264
  public boolean getEnableKeepAlive() {
265
    return enableKeepAlive;
1✔
266
  }
267

268
  /**
269
   * @return interval at which server will be pinged in order to determine if connections are still
270
   *     alive
271
   */
272
  public Duration getKeepAliveTime() {
273
    return keepAliveTime;
1✔
274
  }
275

276
  /**
277
   * @return amount of time that client would wait for the keep alive ping response from the server
278
   *     before closing the connection
279
   */
280
  public Duration getKeepAliveTimeout() {
281
    return keepAliveTimeout;
1✔
282
  }
283

284
  /**
285
   * @return if keep alive ping will be allowed when there are no active RPCs
286
   */
287
  public boolean getKeepAlivePermitWithoutStream() {
288
    return keepAlivePermitWithoutStream;
1✔
289
  }
290

291
  /**
292
   * @return the rpc timeout value
293
   */
294
  public Duration getRpcTimeout() {
295
    return rpcTimeout;
1✔
296
  }
297

298
  /**
299
   * @return frequency at which connection backoff should be reset or null if backoff reset is
300
   *     disabled
301
   */
302
  public Duration getConnectionBackoffResetFrequency() {
303
    return connectionBackoffResetFrequency;
1✔
304
  }
305

306
  /**
307
   * @return frequency at which grpc channel should be moved into an idle state
308
   */
309
  public Duration getGrpcReconnectFrequency() {
310
    return grpcReconnectFrequency;
1✔
311
  }
312

313
  /**
314
   * @return gRPC headers to be added to every call
315
   */
316
  public Metadata getHeaders() {
317
    return headers;
1✔
318
  }
319

320
  /**
321
   * @return gRPC metadata/headers providers to be called on each gRPC request to supply additional
322
   *     headers
323
   */
324
  public Collection<GrpcMetadataProvider> getGrpcMetadataProviders() {
325
    return grpcMetadataProviders;
1✔
326
  }
327

328
  /**
329
   * @return gRPC client interceptors to be added to gRPC channel
330
   */
331
  public Collection<ClientInterceptor> getGrpcClientInterceptors() {
332
    return grpcClientInterceptors;
1✔
333
  }
334

335
  /**
336
   * @return scope to be used for metrics reporting
337
   */
338
  @Nonnull
339
  public Scope getMetricsScope() {
340
    return metricsScope;
1✔
341
  }
342

343
  @Override
344
  public boolean equals(Object o) {
345
    if (this == o) return true;
×
346
    if (o == null || getClass() != o.getClass()) return false;
×
347
    ServiceStubsOptions that = (ServiceStubsOptions) o;
×
348
    return enableHttps == that.enableHttps
×
349
        && enableKeepAlive == that.enableKeepAlive
350
        && keepAlivePermitWithoutStream == that.keepAlivePermitWithoutStream
351
        && Objects.equals(channel, that.channel)
×
352
        && Objects.equals(target, that.target)
×
353
        && Objects.equals(channelInitializer, that.channelInitializer)
×
354
        && Objects.equals(sslContext, that.sslContext)
×
355
        && Objects.equals(healthCheckAttemptTimeout, that.healthCheckAttemptTimeout)
×
356
        && Objects.equals(healthCheckTimeout, that.healthCheckTimeout)
×
357
        && Objects.equals(systemInfoTimeout, that.systemInfoTimeout)
×
358
        && Objects.equals(keepAliveTime, that.keepAliveTime)
×
359
        && Objects.equals(keepAliveTimeout, that.keepAliveTimeout)
×
360
        && Objects.equals(rpcTimeout, that.rpcTimeout)
×
361
        && Objects.equals(connectionBackoffResetFrequency, that.connectionBackoffResetFrequency)
×
362
        && Objects.equals(grpcReconnectFrequency, that.grpcReconnectFrequency)
×
363
        && Objects.equals(headers, that.headers)
×
364
        && Objects.equals(grpcMetadataProviders, that.grpcMetadataProviders)
×
365
        && Objects.equals(grpcClientInterceptors, that.grpcClientInterceptors)
×
366
        && Objects.equals(metricsScope, that.metricsScope);
×
367
  }
368

369
  @Override
370
  public int hashCode() {
371
    return Objects.hash(
×
372
        channel,
373
        target,
374
        channelInitializer,
375
        enableHttps,
×
376
        sslContext,
377
        healthCheckAttemptTimeout,
378
        healthCheckTimeout,
379
        systemInfoTimeout,
380
        enableKeepAlive,
×
381
        keepAliveTime,
382
        keepAliveTimeout,
383
        keepAlivePermitWithoutStream,
×
384
        rpcTimeout,
385
        connectionBackoffResetFrequency,
386
        grpcReconnectFrequency,
387
        headers,
388
        grpcMetadataProviders,
389
        grpcClientInterceptors,
390
        metricsScope);
391
  }
392

393
  @Override
394
  public String toString() {
395
    return "ServiceStubsOptions{"
×
396
        + "channel="
397
        + channel
398
        + ", target='"
399
        + target
400
        + '\''
401
        + ", channelInitializer="
402
        + channelInitializer
403
        + ", enableHttps="
404
        + enableHttps
405
        + ", sslContext="
406
        + sslContext
407
        + ", healthCheckAttemptTimeout="
408
        + healthCheckAttemptTimeout
409
        + ", healthCheckTimeout="
410
        + healthCheckTimeout
411
        + ", systemInfoTimeout="
412
        + systemInfoTimeout
413
        + ", enableKeepAlive="
414
        + enableKeepAlive
415
        + ", keepAliveTime="
416
        + keepAliveTime
417
        + ", keepAliveTimeout="
418
        + keepAliveTimeout
419
        + ", keepAlivePermitWithoutStream="
420
        + keepAlivePermitWithoutStream
421
        + ", rpcTimeout="
422
        + rpcTimeout
423
        + ", connectionBackoffResetFrequency="
424
        + connectionBackoffResetFrequency
425
        + ", grpcReconnectFrequency="
426
        + grpcReconnectFrequency
427
        + ", headers="
428
        + headers
429
        + ", grpcMetadataProviders="
430
        + grpcMetadataProviders
431
        + ", grpcClientInterceptors="
432
        + grpcClientInterceptors
433
        + ", metricsScope="
434
        + metricsScope
435
        + '}';
436
  }
437

438
  public static class Builder<T extends Builder<T>> {
439
    private ManagedChannel channel;
440
    private SslContext sslContext;
441
    private boolean enableHttps;
442
    private String target;
443
    private Consumer<ManagedChannelBuilder<?>> channelInitializer;
444
    private Duration healthCheckAttemptTimeout;
445
    private Duration systemInfoTimeout;
446
    private Duration healthCheckTimeout;
447
    private boolean enableKeepAlive = true;
1✔
448
    private Duration keepAliveTime = Duration.ofSeconds(30);
1✔
449
    private Duration keepAliveTimeout = Duration.ofSeconds(15);
1✔
450
    private boolean keepAlivePermitWithoutStream = true;
1✔
451
    private Duration rpcTimeout = DEFAULT_RPC_TIMEOUT;
1✔
452
    private Duration connectionBackoffResetFrequency = DEFAULT_CONNECTION_BACKOFF_RESET_FREQUENCY;
1✔
453
    private Duration grpcReconnectFrequency = DEFAULT_GRPC_RECONNECT_FREQUENCY;
1✔
454
    private Metadata headers;
455
    private Collection<GrpcMetadataProvider> grpcMetadataProviders;
456
    private Collection<ClientInterceptor> grpcClientInterceptors;
457
    private Scope metricsScope;
458

459
    protected Builder() {}
1✔
460

461
    protected Builder(ServiceStubsOptions options) {
1✔
462
      this.channel = options.channel;
1✔
463
      this.target = options.target;
1✔
464
      this.channelInitializer = options.channelInitializer;
1✔
465
      this.enableHttps = options.enableHttps;
1✔
466
      this.sslContext = options.sslContext;
1✔
467
      this.healthCheckAttemptTimeout = options.healthCheckAttemptTimeout;
1✔
468
      this.healthCheckTimeout = options.healthCheckTimeout;
1✔
469
      this.systemInfoTimeout = options.systemInfoTimeout;
1✔
470
      this.enableKeepAlive = options.enableKeepAlive;
1✔
471
      this.keepAliveTime = options.keepAliveTime;
1✔
472
      this.keepAliveTimeout = options.keepAliveTimeout;
1✔
473
      this.keepAlivePermitWithoutStream = options.keepAlivePermitWithoutStream;
1✔
474
      this.rpcTimeout = options.rpcTimeout;
1✔
475
      this.connectionBackoffResetFrequency = options.connectionBackoffResetFrequency;
1✔
476
      this.grpcReconnectFrequency = options.grpcReconnectFrequency;
1✔
477
      this.headers = options.headers;
1✔
478
      this.grpcMetadataProviders = options.grpcMetadataProviders;
1✔
479
      this.grpcClientInterceptors = options.grpcClientInterceptors;
1✔
480
      this.metricsScope = options.metricsScope;
1✔
481
    }
1✔
482

483
    /**
484
     * Sets a target string, which can be either a valid {@link NameResolver}-compliant URI, or an
485
     * authority string. See {@link ManagedChannelBuilder#forTarget(String)} for more information
486
     * about parameter format. Default is {@link #DEFAULT_LOCAL_DOCKER_TARGET}
487
     *
488
     * <p>Mutually exclusive with {@link #setChannel(ManagedChannel)}.
489
     *
490
     * @return {@code this}
491
     */
492
    public T setTarget(String target) {
493
      this.target = target;
1✔
494
      return self();
1✔
495
    }
496

497
    /**
498
     * Gives an opportunity to provide some additional configuration to the channel builder or
499
     * override configurations done by the Temporal Stubs. Currently, Temporal Stubs use {@link
500
     * io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder} to create a {@link ManagedChannel}.
501
     *
502
     * <p>Advanced API
503
     *
504
     * <p>Mutually exclusive with {@link #setChannel(ManagedChannel)}.
505
     *
506
     * @param channelInitializer listener that will be called as a last step of channel creation if
507
     *     Stubs are configured with {@link Builder#setTarget(String)}. The listener is called with
508
     *     an instance of {@link io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder} that will
509
     *     be used by Temporal Stubs to create a {@link ManagedChannel}. The builder type may change
510
     *     in the future.
511
     * @return {@code this}
512
     */
513
    public T setChannelInitializer(Consumer<ManagedChannelBuilder<?>> channelInitializer) {
514
      this.channelInitializer = channelInitializer;
1✔
515
      return self();
1✔
516
    }
517

518
    /**
519
     * Sets fully custom user-configured gRPC channel to use.
520
     *
521
     * <p>Before supplying a fully custom channel using this method, it's recommended to first
522
     * consider using {@link #setTarget(String)} + other options of {@link
523
     * WorkflowServiceStubsOptions.Builder} + {@link #setChannelInitializer(Consumer)} for some
524
     * rarely used configuration.<br>
525
     * This option is not intended for the majority of users as it disables some Temporal connection
526
     * management features and can lead to outages if the channel is configured or managed
527
     * improperly.
528
     *
529
     * <p>Mutually exclusive with {@link #setTarget(String)}, {@link
530
     * #setChannelInitializer(Consumer)}, {@link #setSslContext(SslContext)}, {@link
531
     * #setGrpcReconnectFrequency(Duration)} and {@link
532
     * #setConnectionBackoffResetFrequency(Duration)}. These options are ignored if the custom
533
     * channel is supplied.
534
     *
535
     * @return {@code this}
536
     */
537
    public T setChannel(ManagedChannel channel) {
538
      this.channel = channel;
1✔
539
      return self();
1✔
540
    }
541

542
    /**
543
     * Sets gRPC SSL Context to use, used for more advanced scenarios such as mTLS. Supersedes
544
     * enableHttps; Exclusive with channel. Consider using {@link SimpleSslContextBuilder} which
545
     * greatly simplifies creation of the TLS enabled SslContext with client and server key
546
     * validation.
547
     *
548
     * @return {@code this}
549
     */
550
    public T setSslContext(SslContext sslContext) {
551
      this.sslContext = sslContext;
1✔
552
      return self();
1✔
553
    }
554

555
    /**
556
     * Sets option to enable SSL/TLS/HTTPS for gRPC.
557
     *
558
     * <p>Mutually exclusive with channel; Ignored and assumed {@code true} if {@link
559
     * #setSslContext(SslContext)} is specified.
560
     *
561
     * @return {@code this}
562
     */
563
    public T setEnableHttps(boolean enableHttps) {
564
      this.enableHttps = enableHttps;
1✔
565
      return self();
1✔
566
    }
567

568
    /**
569
     * Sets frequency at which gRPC connection backoff should be reset practically defining an upper
570
     * limit for the maximum backoff duration. If set to null then no backoff reset will be
571
     * performed and we'll rely on default gRPC backoff behavior defined in
572
     * ExponentialBackoffPolicy.
573
     *
574
     * <p>Mutually exclusive with {@link #setChannel(ManagedChannel)}.
575
     *
576
     * @param connectionBackoffResetFrequency frequency, defaults to once every 10 seconds. Set to
577
     *     null in order to disable this feature
578
     * @see ManagedChannel#resetConnectBackoff()
579
     * @return {@code this}
580
     */
581
    public T setConnectionBackoffResetFrequency(Duration connectionBackoffResetFrequency) {
582
      this.connectionBackoffResetFrequency = connectionBackoffResetFrequency;
×
583
      return self();
×
584
    }
585

586
    /**
587
     * Sets frequency at which gRPC channel will be moved into an idle state and triggers tear-down
588
     * of the channel's name resolver and load balancer, while still allowing on-going RPCs on the
589
     * channel to continue. New RPCs on the channel will trigger creation of a new connection. This
590
     * allows worker to connect to a new temporal backend host periodically avoiding hot spots and
591
     * resulting in a more even connection distribution.
592
     *
593
     * <p>Mutually exclusive with {@link #setChannel(ManagedChannel)}.
594
     *
595
     * @param grpcReconnectFrequency frequency, defaults to once every 1 minute. Set to null in
596
     *     order to disable this feature
597
     * @see ManagedChannel#enterIdle()
598
     * @return {@code this}
599
     */
600
    public T setGrpcReconnectFrequency(Duration grpcReconnectFrequency) {
601
      this.grpcReconnectFrequency = grpcReconnectFrequency;
×
602
      return self();
×
603
    }
604

605
    /**
606
     * @param headers gRPC headers to be added to every call
607
     * @return {@code this}
608
     */
609
    public T setHeaders(Metadata headers) {
610
      this.headers = headers;
×
611
      return self();
×
612
    }
613

614
    /**
615
     * @param grpcMetadataProvider gRPC metadata/headers provider to be called on each gRPC request
616
     *     to supply additional headers
617
     * @return {@code this}
618
     */
619
    public T addGrpcMetadataProvider(GrpcMetadataProvider grpcMetadataProvider) {
620
      if (this.grpcMetadataProviders == null) {
1!
621
        this.grpcMetadataProviders = new ArrayList<>();
1✔
622
      }
623
      this.grpcMetadataProviders.add(grpcMetadataProvider);
1✔
624
      return self();
1✔
625
    }
626

627
    /**
628
     * Add a {@link AuthorizationGrpcMetadataProvider} to the gRPC metadata providers that supplies
629
     * an authentication token on each gRPC request.
630
     *
631
     * @param apiKey authentication token supplier to be called on each gRPC request. SDK will
632
     *     automatically add the "Bearer " prefix.
633
     * @return {@code this}
634
     */
635
    public T addApiKey(AuthorizationTokenSupplier apiKey) {
636
      addGrpcMetadataProvider(
×
637
          new AuthorizationGrpcMetadataProvider(
638
              () -> {
639
                return "Bearer " + apiKey.supply();
×
640
              }));
641
      return self();
×
642
    }
643

644
    /**
645
     * @param grpcMetadataProviders gRPC metadata/headers providers to be called on each gRPC
646
     *     request to supply additional headers
647
     * @return {@code this}
648
     */
649
    public T setGrpcMetadataProviders(Collection<GrpcMetadataProvider> grpcMetadataProviders) {
650
      this.grpcMetadataProviders = grpcMetadataProviders;
×
651
      return self();
×
652
    }
653

654
    /**
655
     * @param grpcClientInterceptor gRPC client interceptor to be added to gRPC channel
656
     * @return {@code this}
657
     */
658
    public T addGrpcClientInterceptor(ClientInterceptor grpcClientInterceptor) {
659
      if (this.grpcClientInterceptors == null) {
1!
660
        grpcClientInterceptors = new ArrayList<>();
1✔
661
      }
662
      this.grpcClientInterceptors.add(grpcClientInterceptor);
1✔
663
      return self();
1✔
664
    }
665

666
    /**
667
     * @param grpcClientInterceptors gRPC client interceptors to be added to gRPC channel
668
     * @return {@code this}
669
     */
670
    public T setGrpcClientInterceptors(Collection<ClientInterceptor> grpcClientInterceptors) {
671
      this.grpcClientInterceptors = grpcClientInterceptors;
1✔
672
      return self();
1✔
673
    }
674

675
    /**
676
     * Sets the scope to be used for metrics reporting. Optional. Default is to not report metrics.
677
     *
678
     * <p>This method should be used to integrate client and workers with external metrics and
679
     * monitoring systems.
680
     *
681
     * <p>Example:<br>
682
     *
683
     * <pre>{@code
684
     * PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
685
     * StatsReporter reporter = new MicrometerClientStatsReporter(registry);
686
     * Scope scope = new RootScopeBuilder().reporter(reporter).reportEvery(Duration.ofSeconds(10));
687
     * WorkflowServiceStubsOptions options =
688
     *     WorkflowServiceStubsOptions.newBuilder()
689
     *         .setMetricsScope(scope)
690
     *         .build();
691
     * }</pre>
692
     *
693
     * <p>Note: Don't mock {@link Scope} in tests! If you need to verify the metrics behavior,
694
     * create a real Scope and mock, stub or spy a reporter instance:<br>
695
     *
696
     * <pre>{@code
697
     * StatsReporter reporter = mock(StatsReporter.class);
698
     * Scope metricsScope =
699
     *     new RootScopeBuilder()
700
     *         .reporter(reporter)
701
     *         .reportEvery(com.uber.m3.util.Duration.ofMillis(10));
702
     * }</pre>
703
     *
704
     * @param metricsScope the scope to be used for metrics reporting.
705
     * @return {@code this}
706
     */
707
    public T setMetricsScope(Scope metricsScope) {
708
      this.metricsScope = metricsScope;
1✔
709
      return self();
1✔
710
    }
711

712
    /**
713
     * Set the time to wait between service responses on each health check.
714
     *
715
     * @return {@code this}
716
     * @deprecated {@link #rpcTimeout} is now used as an attempt timeout.
717
     */
718
    @Deprecated
719
    public T setHealthCheckAttemptTimeout(Duration healthCheckAttemptTimeout) {
720
      this.healthCheckAttemptTimeout = healthCheckAttemptTimeout;
×
721
      return self();
×
722
    }
723

724
    /**
725
     * Set a HealthCheckTimeout after which to stop waiting while checking server connection when
726
     * creating new client.
727
     *
728
     * @return {@code this}
729
     * @deprecated Use more explicit {@link
730
     *     WorkflowServiceStubs#newConnectedServiceStubs(WorkflowServiceStubsOptions, Duration)}
731
     *     with a timeout parameter instead
732
     */
733
    @Deprecated
734
    public T setHealthCheckTimeout(Duration healthCheckTimeout) {
735
      this.healthCheckTimeout = healthCheckTimeout;
×
736
      return self();
×
737
    }
738

739
    /**
740
     * Set a SystemInfoTimeout that specifies how long the client tries to fetch server
741
     * capabilities.
742
     *
743
     * @return {@code this}
744
     */
745
    public T setSystemInfoTimeout(Duration systemInfoTimeout) {
746
      this.systemInfoTimeout = systemInfoTimeout;
1✔
747
      return self();
1✔
748
    }
749

750
    /**
751
     * Enables keep alive ping from client to the server, which can help drop abruptly closed
752
     * connections faster.
753
     *
754
     * <p>Default is true
755
     *
756
     * @return {@code this}
757
     */
758
    public T setEnableKeepAlive(boolean enableKeepAlive) {
759
      this.enableKeepAlive = enableKeepAlive;
×
760
      return self();
×
761
    }
762

763
    /**
764
     * After a duration of this time if the client doesn't see any activity it pings the server to
765
     * see if the transport is still alive. If set below 10s, a minimum value of 10s will be used
766
     * instead.
767
     *
768
     * <p>Default is 30s
769
     *
770
     * @return {@code this}
771
     */
772
    public T setKeepAliveTime(Duration keepAliveTime) {
773
      this.keepAliveTime = keepAliveTime;
×
774
      return self();
×
775
    }
776

777
    /**
778
     * After having pinged for keepalive check, the client waits for a duration of Timeout and if no
779
     * activity is seen even after that the connection is closed.
780
     *
781
     * <p>Default is 15s
782
     *
783
     * @return {@code this}
784
     */
785
    public T setKeepAliveTimeout(Duration keepAliveTimeout) {
786
      this.keepAliveTimeout = keepAliveTimeout;
×
787
      return self();
×
788
    }
789

790
    /**
791
     * If true, client sends keepalive pings even with no active RPCs. If false, when there are no
792
     * active RPCs, Time and Timeout will be ignored and no keepalive pings will be sent. * @return
793
     *
794
     * <p>Default is true
795
     *
796
     * @return {@code this}
797
     */
798
    public T setKeepAlivePermitWithoutStream(boolean keepAlivePermitWithoutStream) {
799
      this.keepAlivePermitWithoutStream = keepAlivePermitWithoutStream;
×
800
      return self();
×
801
    }
802

803
    /**
804
     * Sets the rpc timeout value. Default is 10 seconds.
805
     *
806
     * @return {@code this}
807
     */
808
    public T setRpcTimeout(Duration timeout) {
809
      this.rpcTimeout = Objects.requireNonNull(timeout);
1✔
810
      return self();
1✔
811
    }
812

813
    /**
814
     * @return {@code this}
815
     */
816
    @SuppressWarnings("unchecked")
817
    private T self() {
818
      return (T) this;
1✔
819
    }
820

821
    /**
822
     * @return Built ServiceStubOptions object with the specified params
823
     */
824
    public ServiceStubsOptions build() {
825
      return new ServiceStubsOptions(
1✔
826
          this.channel,
827
          this.target,
828
          this.channelInitializer,
829
          this.enableHttps,
830
          this.sslContext,
831
          this.healthCheckAttemptTimeout,
832
          this.healthCheckTimeout,
833
          this.systemInfoTimeout,
834
          this.enableKeepAlive,
835
          this.keepAliveTime,
836
          this.keepAliveTimeout,
837
          this.keepAlivePermitWithoutStream,
838
          this.rpcTimeout,
839
          this.connectionBackoffResetFrequency,
840
          this.grpcReconnectFrequency,
841
          this.headers,
842
          this.grpcMetadataProviders,
843
          this.grpcClientInterceptors,
844
          this.metricsScope);
845
    }
846

847
    public ServiceStubsOptions validateAndBuildWithDefaults() {
848
      if (this.target != null && this.channel != null) {
1!
849
        throw new IllegalStateException(
×
850
            "Only one of the 'target' or 'channel' options can be set at a time");
851
      }
852

853
      if (this.channelInitializer != null && this.channel != null) {
1!
854
        throw new IllegalStateException(
×
855
            "Only one of the 'channelInitializer' or 'channel' options can be set at a time");
856
      }
857

858
      if (this.sslContext != null && this.channel != null) {
1!
859
        throw new IllegalStateException(
×
860
            "Only one of the 'sslContext' or 'channel' options can be set at a time");
861
      }
862

863
      if (this.enableHttps && this.channel != null) {
1!
864
        throw new IllegalStateException(
×
865
            "Only one of the 'enableHttps' or 'channel' options can be set at a time");
866
      }
867

868
      String target =
869
          this.target == null && this.channel == null ? DEFAULT_LOCAL_DOCKER_TARGET : this.target;
1✔
870

871
      Metadata headers = this.headers != null ? this.headers : new Metadata();
1✔
872
      Collection<GrpcMetadataProvider> grpcMetadataProviders =
1✔
873
          MoreObjects.firstNonNull(this.grpcMetadataProviders, Collections.emptyList());
1✔
874
      Collection<ClientInterceptor> grpcClientInterceptors =
1✔
875
          MoreObjects.firstNonNull(this.grpcClientInterceptors, Collections.emptyList());
1✔
876

877
      Scope metricsScope = this.metricsScope != null ? this.metricsScope : new NoopScope();
1✔
878
      Duration healthCheckAttemptTimeout =
879
          this.healthCheckAttemptTimeout != null
1✔
880
              ? this.healthCheckAttemptTimeout
1✔
881
              : Duration.ofSeconds(5);
1✔
882
      Duration healthCheckTimeout =
883
          this.healthCheckTimeout != null ? this.healthCheckTimeout : Duration.ofSeconds(10);
1✔
884

885
      Duration systemInfoTimeout =
886
          this.systemInfoTimeout != null ? this.systemInfoTimeout : Duration.ofSeconds(5);
1✔
887
      return new ServiceStubsOptions(
1✔
888
          this.channel,
889
          target,
890
          this.channelInitializer,
891
          this.enableHttps,
892
          this.sslContext,
893
          healthCheckAttemptTimeout,
894
          healthCheckTimeout,
895
          systemInfoTimeout,
896
          this.enableKeepAlive,
897
          this.keepAliveTime,
898
          this.keepAliveTimeout,
899
          this.keepAlivePermitWithoutStream,
900
          this.rpcTimeout,
901
          this.connectionBackoffResetFrequency,
902
          this.grpcReconnectFrequency,
903
          headers,
904
          grpcMetadataProviders,
905
          grpcClientInterceptors,
906
          metricsScope);
907
    }
908
  }
909
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc