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

temporalio / sdk-java / #411

26 Oct 2026 06:32PM UTC coverage: 70.215% (+0.09%) from 70.128%
#411

push

github

web-flow
Add Required PR Checks job to gate merges (#3162)

8125 of 13662 branches covered (59.47%)

Branch coverage included in aggregate %.

32703 of 44485 relevant lines covered (73.51%)

0.74 hits per line

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

84.52
/temporal-sdk/src/main/java/io/temporal/client/WorkflowClientOptions.java
1
package io.temporal.client;
2

3
import com.google.common.base.Preconditions;
4
import io.temporal.api.enums.v1.QueryRejectCondition;
5
import io.temporal.common.Experimental;
6
import io.temporal.common.context.ContextPropagator;
7
import io.temporal.common.converter.DataConverter;
8
import io.temporal.common.converter.GlobalDataConverter;
9
import io.temporal.common.interceptors.WorkflowClientInterceptor;
10
import io.temporal.payload.storage.ExternalStorage;
11
import java.lang.management.ManagementFactory;
12
import java.time.Duration;
13
import java.util.Arrays;
14
import java.util.Collections;
15
import java.util.List;
16
import java.util.Objects;
17
import javax.annotation.Nullable;
18

19
/** Options for WorkflowClient configuration. */
20
public final class WorkflowClientOptions {
21

22
  private static final WorkflowClientOptions DEFAULT_INSTANCE;
23
  private static final String DEFAULT_NAMESPACE = "default";
24
  private static final String DEFAULT_BINARY_CHECKSUM = "";
25

26
  static {
27
    DEFAULT_INSTANCE = newBuilder().build();
1 ✔
28
  }
29

30
  public static Builder newBuilder() {
31
    return new Builder();
1 ✔
32
  }
33

34
  public static Builder newBuilder(WorkflowClientOptions options) {
35
    return new Builder(options);
1 ✔
36
  }
37

38
  public WorkflowClientOptions.Builder toBuilder() {
39
    return new WorkflowClientOptions.Builder(this);
1 ✔
40
  }
41

42
  public static WorkflowClientOptions getDefaultInstance() {
43
    return DEFAULT_INSTANCE;
1 ✔
44
  }
45

46
  public static final class Builder {
47

48
    private String namespace;
49
    private DataConverter dataConverter;
50
    private WorkflowClientInterceptor[] interceptors;
51
    private String identity;
52
    private String binaryChecksum;
53
    private List<ContextPropagator> contextPropagators;
54
    private QueryRejectCondition queryRejectCondition;
55
    private WorkflowClientPlugin[] plugins;
56
    private Duration workerHeartbeatInterval;
57
    private boolean disableWorkerEnvironmentInfo;
58
    private ExternalStorage externalStorage;
59

60
    private Builder() {}
61

62
    private Builder(WorkflowClientOptions options) {
1 ✔
63
      if (options == null) {
1 ✔
64
        return;
1 ✔
65
      }
66
      namespace = options.namespace;
1 ✔
67
      dataConverter = options.dataConverter;
1 ✔
68
      interceptors = options.interceptors;
1 ✔
69
      identity = options.identity;
1 ✔
70
      binaryChecksum = options.binaryChecksum;
1 ✔
71
      contextPropagators = options.contextPropagators;
1 ✔
72
      queryRejectCondition = options.queryRejectCondition;
1 ✔
73
      plugins = options.plugins;
1 ✔
74
      workerHeartbeatInterval = options.workerHeartbeatInterval;
1 ✔
75
      disableWorkerEnvironmentInfo = options.disableWorkerEnvironmentInfo;
1 ✔
76
      externalStorage = options.externalStorage;
1 ✔
77
    }
1 ✔
78

79
    public Builder setNamespace(String namespace) {
80
      this.namespace = namespace;
1 ✔
81
      return this;
1 ✔
82
    }
83

84
    /**
85
     * Overrides a data converter implementation used serialize workflow and activity arguments and
86
     * results.
87
     *
88
     * <p>Default is {@link DataConverter#getDefaultInstance()}.
89
     */
90
    public Builder setDataConverter(DataConverter dataConverter) {
91
      this.dataConverter = Objects.requireNonNull(dataConverter);
1 ✔
92
      return this;
1 ✔
93
    }
94

95
    /**
96
     * External storage configuration used to store/retrieve large payloads.
97
     *
98
     * <p>n.b. This is currently a no-op. External storage has not been fully integrated yet.
99
     *
100
     * <p>Defaults to null.
101
     */
102
    @Experimental
103
    public Builder setExternalStorage(@Nullable ExternalStorage externalStorage) {
104
      this.externalStorage = externalStorage;
1 ✔
105
      return this;
1 ✔
106
    }
107

108
    /**
109
     * Interceptor used to intercept workflow client calls.
110
     *
111
     * @param interceptors not null
112
     */
113
    public Builder setInterceptors(WorkflowClientInterceptor... interceptors) {
114
      this.interceptors = Objects.requireNonNull(interceptors);
1 ✔
115
      return this;
1 ✔
116
    }
117

118
    /**
119
     * Override human readable identity of the worker. Identity is used to identify a worker and is
120
     * recorded in the workflow history events. For example when a worker gets an activity task the
121
     * correspondent ActivityTaskStarted event contains the worker identity as a field. Default is
122
     * whatever <code>(ManagementFactory.getRuntimeMXBean().getName()
123
     * </code> returns.
124
     */
125
    public Builder setIdentity(String identity) {
126
      this.identity = identity;
1 ✔
127
      return this;
1 ✔
128
    }
129

130
    /**
131
     * Sets worker binary checksum, which gets propagated in all history events and can be used for
132
     * auto-reset assuming that every build has a new unique binary checksum. Can be null.
133
     *
134
     * @deprecated use {@link io.temporal.worker.WorkerOptions.Builder#setBuildId(String)} instead.
135
     */
136
    @Deprecated
137
    public Builder setBinaryChecksum(String binaryChecksum) {
138
      this.binaryChecksum = binaryChecksum;
1 ✔
139
      return this;
1 ✔
140
    }
141

142
    /**
143
     * @param contextPropagators specifies the list of context propagators to use with the client.
144
     */
145
    public Builder setContextPropagators(List<ContextPropagator> contextPropagators) {
146
      this.contextPropagators = contextPropagators;
1 ✔
147
      return this;
1 ✔
148
    }
149

150
    /**
151
     * Should a query be rejected by closed and failed workflows.
152
     *
153
     * <p>Default is {@link QueryRejectCondition#QUERY_REJECT_CONDITION_UNSPECIFIED} which means
154
     * that closed and failed workflows are still queryable.
155
     */
156
    public Builder setQueryRejectCondition(QueryRejectCondition queryRejectCondition) {
157
      this.queryRejectCondition = queryRejectCondition;
1 ✔
158
      return this;
1 ✔
159
    }
160

161
    /**
162
     * Sets the workflow client plugins to use with this client. Plugins can modify client
163
     * configuration.
164
     *
165
     * <p>Plugins that also implement {@link io.temporal.worker.WorkerPlugin} are automatically
166
     * propagated to workers created from this client.
167
     *
168
     * @param plugins the workflow client plugins to use
169
     * @return this builder for chaining
170
     * @see WorkflowClientPlugin
171
     * @see io.temporal.worker.WorkerPlugin
172
     */
173
    @Experimental
174
    public Builder setPlugins(WorkflowClientPlugin... plugins) {
175
      this.plugins = Objects.requireNonNull(plugins);
1 ✔
176
      return this;
1 ✔
177
    }
178

179
    /**
180
     * Sets the interval at which workers send heartbeat RPCs to the server. If not set or set to
181
     * zero, defaults to 60 seconds. A negative duration disables heartbeating. Positive values must
182
     * be between 1 and 60 seconds inclusive.
183
     *
184
     * @param workerHeartbeatInterval the heartbeat interval, or a negative duration to disable
185
     */
186
    @Experimental
187
    public Builder setWorkerHeartbeatInterval(Duration workerHeartbeatInterval) {
188
      this.workerHeartbeatInterval = workerHeartbeatInterval;
1 ✔
189
      return this;
1 ✔
190
    }
191

192
    /**
193
     * Disables reporting runtime versions (JVM, detected Graal native images, and Kotlin), detected
194
     * hosting environments (Docker, Kubernetes, cloud platforms), and OS platform in worker
195
     * heartbeats. This information is sent once per worker, with the first heartbeat accepted by
196
     * the server.
197
     *
198
     * @param disableWorkerEnvironmentInfo true to omit environment information from heartbeats
199
     */
200
    @Experimental
201
    public Builder setDisableWorkerEnvironmentInfo(boolean disableWorkerEnvironmentInfo) {
202
      this.disableWorkerEnvironmentInfo = disableWorkerEnvironmentInfo;
×
203
      return this;
×
204
    }
205

206
    public WorkflowClientOptions build() {
207
      return new WorkflowClientOptions(
1 ✔
208
          namespace,
209
          dataConverter,
210
          interceptors,
211
          identity,
212
          binaryChecksum,
213
          contextPropagators,
214
          queryRejectCondition,
215
          plugins == null ? EMPTY_PLUGINS : plugins,
1 ✔
216
          resolveHeartbeatInterval(workerHeartbeatInterval),
1 ✔
217
          disableWorkerEnvironmentInfo,
218
          externalStorage);
219
    }
220

221
    /**
222
     * Validates options and builds with defaults applied.
223
     *
224
     * <p>Note: If plugins are configured via {@link #setPlugins(WorkflowClientPlugin...)}, they
225
     * will have an opportunity to modify options after this method is called, when the options are
226
     * passed to {@link WorkflowClient#newInstance}. This means validation performed here occurs
227
     * before plugin modifications. In most cases, users should simply call {@link #build()} and let
228
     * the client creation handle validation.
229
     *
230
     * @return validated options with defaults applied
231
     */
232
    public WorkflowClientOptions validateAndBuildWithDefaults() {
233
      String name = identity == null ? ManagementFactory.getRuntimeMXBean().getName() : identity;
1 ✔
234
      return new WorkflowClientOptions(
1 ✔
235
          namespace == null ? DEFAULT_NAMESPACE : namespace,
1 ✔
236
          dataConverter == null ? GlobalDataConverter.get() : dataConverter,
1 ✔
237
          interceptors == null ? EMPTY_INTERCEPTOR_ARRAY : interceptors,
1 ✔
238
          name,
239
          binaryChecksum == null ? DEFAULT_BINARY_CHECKSUM : binaryChecksum,
1 ✔
240
          contextPropagators == null ? EMPTY_CONTEXT_PROPAGATORS : contextPropagators,
1 ✔
241
          queryRejectCondition == null
1 ✔
242
              ? QueryRejectCondition.QUERY_REJECT_CONDITION_UNSPECIFIED
1 ✔
243
              : queryRejectCondition,
1 ✔
244
          plugins == null ? EMPTY_PLUGINS : plugins,
1 ✔
245
          resolveHeartbeatInterval(workerHeartbeatInterval),
1 ✔
246
          disableWorkerEnvironmentInfo,
247
          externalStorage);
248
    }
249

250
    private static Duration resolveHeartbeatInterval(Duration raw) {
251
      if (raw == null || raw.isZero()) {
1 !
252
        return Duration.ofSeconds(60);
1 ✔
253
      }
254
      if (raw.isNegative()) {
1 ✔
255
        return raw;
1 ✔
256
      }
257
      Preconditions.checkArgument(
1 ✔
258
          raw.compareTo(Duration.ofSeconds(1)) >= 0 && raw.compareTo(Duration.ofSeconds(60)) <= 0,
1 !
259
          "workerHeartbeatInterval must be between 1s and 60s, got %s",
260
          raw);
261
      return raw;
1 ✔
262
    }
263
  }
264

265
  private static final WorkflowClientInterceptor[] EMPTY_INTERCEPTOR_ARRAY =
1 ✔
266
      new WorkflowClientInterceptor[0];
267

268
  private static final List<ContextPropagator> EMPTY_CONTEXT_PROPAGATORS = Collections.emptyList();
1 ✔
269

270
  private static final WorkflowClientPlugin[] EMPTY_PLUGINS = new WorkflowClientPlugin[0];
1 ✔
271

272
  private final String namespace;
273

274
  private final DataConverter dataConverter;
275

276
  private final WorkflowClientInterceptor[] interceptors;
277

278
  private final String identity;
279

280
  private final String binaryChecksum;
281

282
  private final List<ContextPropagator> contextPropagators;
283

284
  private final QueryRejectCondition queryRejectCondition;
285

286
  private final WorkflowClientPlugin[] plugins;
287

288
  private final Duration workerHeartbeatInterval;
289

290
  private final boolean disableWorkerEnvironmentInfo;
291

292
  private final @Nullable ExternalStorage externalStorage;
293

294
  private WorkflowClientOptions(
295
      String namespace,
296
      DataConverter dataConverter,
297
      WorkflowClientInterceptor[] interceptors,
298
      String identity,
299
      String binaryChecksum,
300
      List<ContextPropagator> contextPropagators,
301
      QueryRejectCondition queryRejectCondition,
302
      WorkflowClientPlugin[] plugins,
303
      Duration workerHeartbeatInterval,
304
      boolean disableWorkerEnvironmentInfo,
305
      @Nullable ExternalStorage externalStorage) {
1 ✔
306
    this.namespace = namespace;
1 ✔
307
    this.dataConverter = dataConverter;
1 ✔
308
    this.interceptors = interceptors;
1 ✔
309
    this.identity = identity;
1 ✔
310
    this.binaryChecksum = binaryChecksum;
1 ✔
311
    this.contextPropagators = contextPropagators;
1 ✔
312
    this.queryRejectCondition = queryRejectCondition;
1 ✔
313
    this.plugins = plugins;
1 ✔
314
    this.workerHeartbeatInterval = workerHeartbeatInterval;
1 ✔
315
    this.disableWorkerEnvironmentInfo = disableWorkerEnvironmentInfo;
1 ✔
316
    this.externalStorage = externalStorage;
1 ✔
317
  }
1 ✔
318

319
  /**
320
   * Should be non-null on a valid instance
321
   *
322
   * @return namespace
323
   */
324
  public String getNamespace() {
325
    return namespace;
1 ✔
326
  }
327

328
  public DataConverter getDataConverter() {
329
    return dataConverter;
1 ✔
330
  }
331

332
  /** External storage used to offload large payloads or null when disabled. */
333
  @Experimental
334
  @Nullable
335
  public ExternalStorage getExternalStorage() {
336
    return externalStorage;
1 ✔
337
  }
338

339
  public WorkflowClientInterceptor[] getInterceptors() {
340
    return interceptors;
1 ✔
341
  }
342

343
  /**
344
   * Should be non-null on a valid instance
345
   *
346
   * @return identity
347
   */
348
  public String getIdentity() {
349
    return identity;
1 ✔
350
  }
351

352
  @Deprecated
353
  public String getBinaryChecksum() {
354
    return binaryChecksum;
1 ✔
355
  }
356

357
  /**
358
   * @return the list of context propagators to use with the client.
359
   */
360
  public List<ContextPropagator> getContextPropagators() {
361
    return contextPropagators;
1 ✔
362
  }
363

364
  public QueryRejectCondition getQueryRejectCondition() {
365
    return queryRejectCondition;
1 ✔
366
  }
367

368
  /**
369
   * Returns the workflow client plugins configured for this client.
370
   *
371
   * <p>Plugins that also implement {@link io.temporal.worker.WorkerPlugin} are automatically
372
   * propagated to workers created from this client.
373
   *
374
   * @return the array of workflow client plugins, never null
375
   */
376
  @Experimental
377
  public WorkflowClientPlugin[] getPlugins() {
378
    return plugins;
1 ✔
379
  }
380

381
  /**
382
   * Returns the worker heartbeat interval. Defaults to 60 seconds if not configured. A negative
383
   * duration means heartbeating is explicitly disabled.
384
   */
385
  @Experimental
386
  public Duration getWorkerHeartbeatInterval() {
387
    return workerHeartbeatInterval;
1 ✔
388
  }
389

390
  /** Returns true when runtime, hosting, and platform information is omitted from heartbeats. */
391
  @Experimental
392
  public boolean isWorkerEnvironmentInfoDisabled() {
393
    return disableWorkerEnvironmentInfo;
1 ✔
394
  }
395

396
  @Override
397
  public String toString() {
398
    return "WorkflowClientOptions{"
×
399
        + "namespace='"
400
        + namespace
401
        + '\''
402
        + ", dataConverter="
403
        + dataConverter
404
        + ", interceptors="
405
        + Arrays.toString(interceptors)
×
406
        + ", identity='"
407
        + identity
408
        + '\''
409
        + ", binaryChecksum='"
410
        + binaryChecksum
411
        + '\''
412
        + ", contextPropagators="
413
        + contextPropagators
414
        + ", queryRejectCondition="
415
        + queryRejectCondition
416
        + ", plugins="
417
        + Arrays.toString(plugins)
×
418
        + ", workerHeartbeatInterval="
419
        + workerHeartbeatInterval
420
        + ", disableWorkerEnvironmentInfo="
421
        + disableWorkerEnvironmentInfo
422
        + ", externalStorage="
423
        + externalStorage
424
        + '}';
425
  }
426

427
  @Override
428
  public boolean equals(Object o) {
429
    if (this == o) return true;
1 !
430
    if (o == null || getClass() != o.getClass()) return false;
1 !
431
    WorkflowClientOptions that = (WorkflowClientOptions) o;
1 ✔
432
    return com.google.common.base.Objects.equal(namespace, that.namespace)
1 !
433
        && com.google.common.base.Objects.equal(dataConverter, that.dataConverter)
1 !
434
        && Arrays.equals(interceptors, that.interceptors)
1 !
435
        && com.google.common.base.Objects.equal(identity, that.identity)
1 !
436
        && com.google.common.base.Objects.equal(binaryChecksum, that.binaryChecksum)
1 !
437
        && com.google.common.base.Objects.equal(contextPropagators, that.contextPropagators)
1 !
438
        && queryRejectCondition == that.queryRejectCondition
439
        && Arrays.equals(plugins, that.plugins)
1 !
440
        && com.google.common.base.Objects.equal(
1 !
441
            workerHeartbeatInterval, that.workerHeartbeatInterval)
442
        && disableWorkerEnvironmentInfo == that.disableWorkerEnvironmentInfo
443
        && com.google.common.base.Objects.equal(externalStorage, that.externalStorage);
1 !
444
  }
445

446
  @Override
447
  public int hashCode() {
448
    return com.google.common.base.Objects.hashCode(
×
449
        namespace,
450
        dataConverter,
451
        Arrays.hashCode(interceptors),
×
452
        identity,
453
        binaryChecksum,
454
        contextPropagators,
455
        queryRejectCondition,
456
        Arrays.hashCode(plugins),
×
457
        workerHeartbeatInterval,
458
        disableWorkerEnvironmentInfo,
×
459
        externalStorage);
460
  }
461
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc