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

temporalio / sdk-java / #175

pending completion
#175

push

github-actions

web-flow
Worker / Build Id versioning (#1786)

Implement new worker build id based versioning feature

236 of 236 new or added lines in 24 files covered. (100.0%)

18343 of 23697 relevant lines covered (77.41%)

0.81 hits per line

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

91.74
/temporal-sdk/src/main/java/io/temporal/client/WorkflowOptions.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.client;
22

23
import com.google.common.base.Objects;
24
import io.temporal.api.enums.v1.WorkflowIdReusePolicy;
25
import io.temporal.common.CronSchedule;
26
import io.temporal.common.MethodRetry;
27
import io.temporal.common.RetryOptions;
28
import io.temporal.common.SearchAttributes;
29
import io.temporal.common.context.ContextPropagator;
30
import io.temporal.internal.common.OptionsUtils;
31
import io.temporal.worker.WorkerFactory;
32
import io.temporal.workflow.Workflow;
33
import java.time.Duration;
34
import java.util.Collection;
35
import java.util.List;
36
import java.util.Map;
37
import javax.annotation.Nullable;
38

39
public final class WorkflowOptions {
40

41
  public static Builder newBuilder() {
42
    return new Builder();
1✔
43
  }
44

45
  public static Builder newBuilder(WorkflowOptions options) {
46
    return new Builder(options);
×
47
  }
48

49
  public static WorkflowOptions getDefaultInstance() {
50
    return DEFAULT_INSTANCE;
×
51
  }
52

53
  private static final WorkflowOptions DEFAULT_INSTANCE;
54

55
  static {
56
    DEFAULT_INSTANCE = WorkflowOptions.newBuilder().build();
1✔
57
  }
1✔
58

59
  public static WorkflowOptions merge(
60
      MethodRetry methodRetry, CronSchedule cronSchedule, WorkflowOptions o) {
61
    if (o == null) {
1✔
62
      o = WorkflowOptions.newBuilder().build();
×
63
    }
64
    String cronAnnotation = cronSchedule == null ? "" : cronSchedule.value();
1✔
65
    return WorkflowOptions.newBuilder()
1✔
66
        .setWorkflowId(o.getWorkflowId())
1✔
67
        .setWorkflowIdReusePolicy(o.getWorkflowIdReusePolicy())
1✔
68
        .setWorkflowRunTimeout(o.getWorkflowRunTimeout())
1✔
69
        .setWorkflowExecutionTimeout(o.getWorkflowExecutionTimeout())
1✔
70
        .setWorkflowTaskTimeout(o.getWorkflowTaskTimeout())
1✔
71
        .setTaskQueue(o.getTaskQueue())
1✔
72
        .setRetryOptions(RetryOptions.merge(methodRetry, o.getRetryOptions()))
1✔
73
        .setCronSchedule(OptionsUtils.merge(cronAnnotation, o.getCronSchedule(), String.class))
1✔
74
        .setMemo(o.getMemo())
1✔
75
        .setSearchAttributes(o.getSearchAttributes())
1✔
76
        .setTypedSearchAttributes(o.getTypedSearchAttributes())
1✔
77
        .setContextPropagators(o.getContextPropagators())
1✔
78
        .setDisableEagerExecution(o.isDisableEagerExecution())
1✔
79
        .validateBuildWithDefaults();
1✔
80
  }
81

82
  public static final class Builder {
83

84
    private String workflowId;
85

86
    private WorkflowIdReusePolicy workflowIdReusePolicy;
87

88
    private Duration workflowRunTimeout;
89

90
    private Duration workflowExecutionTimeout;
91

92
    private Duration workflowTaskTimeout;
93

94
    private String taskQueue;
95

96
    private RetryOptions retryOptions;
97

98
    private String cronSchedule;
99

100
    private Map<String, Object> memo;
101

102
    private Map<String, ?> searchAttributes;
103

104
    private SearchAttributes typedSearchAttributes;
105

106
    private List<ContextPropagator> contextPropagators;
107

108
    private boolean disableEagerExecution;
109

110
    private Builder() {}
111

112
    private Builder(WorkflowOptions options) {
1✔
113
      if (options == null) {
1✔
114
        return;
×
115
      }
116
      this.workflowIdReusePolicy = options.workflowIdReusePolicy;
1✔
117
      this.workflowId = options.workflowId;
1✔
118
      this.workflowTaskTimeout = options.workflowTaskTimeout;
1✔
119
      this.workflowRunTimeout = options.workflowRunTimeout;
1✔
120
      this.workflowExecutionTimeout = options.workflowExecutionTimeout;
1✔
121
      this.taskQueue = options.taskQueue;
1✔
122
      this.retryOptions = options.retryOptions;
1✔
123
      this.cronSchedule = options.cronSchedule;
1✔
124
      this.memo = options.memo;
1✔
125
      this.searchAttributes = options.searchAttributes;
1✔
126
      this.typedSearchAttributes = options.typedSearchAttributes;
1✔
127
      this.contextPropagators = options.contextPropagators;
1✔
128
      this.disableEagerExecution = options.disableEagerExecution;
1✔
129
    }
1✔
130

131
    /**
132
     * Workflow id to use when starting. If not specified a UUID is generated. Note that it is
133
     * dangerous as in case of client side retries no deduplication will happen based on the
134
     * generated id. So prefer assigning business meaningful ids if possible.
135
     */
136
    public Builder setWorkflowId(String workflowId) {
137
      this.workflowId = workflowId;
1✔
138
      return this;
1✔
139
    }
140

141
    /**
142
     * Specifies server behavior if a completed workflow with the same id exists. Note that under no
143
     * conditions Temporal allows two workflows with the same namespace and workflow id run
144
     * simultaneously.
145
     *
146
     * <p>Default value if not set: <b>AllowDuplicate</b>
147
     *
148
     * <ul>
149
     *   <li><b>AllowDuplicate</b> allows a new run regardless of the previous run's final status.
150
     *       The previous run still must be closed or the new run will be rejected.
151
     *   <li><b>AllowDuplicateFailedOnly</b> allows a new run if the previous run failed, was
152
     *       canceled, or terminated.
153
     *   <li><b>RejectDuplicate</b> never allows a new run, regardless of the previous run's final
154
     *       status.
155
     *   <li><b>TerminateIfRunning</b> is the same as <b>AllowDuplicate</b>, but if there exists a
156
     *       not-closed run in progress, it will be terminated.
157
     * </ul>
158
     */
159
    public Builder setWorkflowIdReusePolicy(WorkflowIdReusePolicy workflowIdReusePolicy) {
160
      this.workflowIdReusePolicy = workflowIdReusePolicy;
1✔
161
      return this;
1✔
162
    }
163

164
    /**
165
     * The time after which a workflow run is automatically terminated by Temporal service with
166
     * WORKFLOW_EXECUTION_TIMED_OUT status.
167
     *
168
     * <p>When a workflow reaches Workflow Run Timeout, it can't make any progress after that. Do
169
     * not rely on this timeout in workflow implementation or business logic. This timeout is not
170
     * designed to be handled in workflow code to perform any logic in case of timeout. Consider
171
     * using workflow timers instead.
172
     *
173
     * <p>If you catch yourself setting this timeout to very small values, you're likely using it
174
     * wrong.
175
     *
176
     * <p>Example: If Workflow Run Timeout is 30 seconds and the network was unavailable for 1
177
     * minute, workflows that were scheduled before the network blip will never have a chance to
178
     * make progress or react, and will be terminated. <br>
179
     * A timer that is scheduled in the workflow code using {@link Workflow#newTimer(Duration)} will
180
     * handle this situation gracefully. A workflow with such a timer will start after the network
181
     * blip. If it started before the network blip and the timer fires during the network blip, it
182
     * will get delivered after connectivity is restored and the workflow will be able to resume.
183
     */
184
    public Builder setWorkflowRunTimeout(Duration workflowRunTimeout) {
185
      this.workflowRunTimeout = workflowRunTimeout;
1✔
186
      return this;
1✔
187
    }
188

189
    /**
190
     * The time after which workflow execution (which includes run retries and continue as new) is
191
     * automatically terminated by Temporal service with WORKFLOW_EXECUTION_TIMED_OUT status.
192
     *
193
     * <p>When a workflow reaches Workflow Execution Timeout, it can't make any progress after that.
194
     * Do not rely on this timeout in workflow implementation or business logic. This timeout is not
195
     * designed to be handled in workflow code to perform any logic in case of timeout. Consider
196
     * using workflow timers instead.
197
     *
198
     * <p>If you catch yourself setting this timeout to very small values, you're likely using it
199
     * wrong.
200
     *
201
     * <p>Example: If Workflow Execution Timeout is 30 seconds and the network was unavailable for 1
202
     * minute, workflows that were scheduled before the network blip will never have a chance to
203
     * make progress or react, and will be terminated. <br>
204
     * A timer that is scheduled in the workflow code using {@link Workflow#newTimer(Duration)} will
205
     * handle this situation gracefully. A workflow with such a timer will start after the network
206
     * blip. If it started before the network blip and the timer fires during the network blip, it
207
     * will get delivered after connectivity is restored and the workflow will be able to resume.
208
     */
209
    public Builder setWorkflowExecutionTimeout(Duration workflowExecutionTimeout) {
210
      this.workflowExecutionTimeout = workflowExecutionTimeout;
1✔
211
      return this;
1✔
212
    }
213

214
    /**
215
     * Maximum execution time of a single Workflow Task. In the majority of cases there is no need
216
     * to change this timeout. Note that this timeout is not related to the overall Workflow
217
     * duration in any way. It defines for how long the Workflow can get blocked in the case of a
218
     * Workflow Worker crash.
219
     *
220
     * <p>Default is 10 seconds. Maximum value allowed by the Temporal Server is 1 minute.
221
     */
222
    public Builder setWorkflowTaskTimeout(Duration workflowTaskTimeout) {
223
      this.workflowTaskTimeout = workflowTaskTimeout;
1✔
224
      return this;
1✔
225
    }
226

227
    /**
228
     * Task queue to use for workflow tasks. It should match a task queue specified when creating a
229
     * {@link io.temporal.worker.Worker} that hosts the workflow code.
230
     */
231
    public Builder setTaskQueue(String taskQueue) {
232
      this.taskQueue = taskQueue;
1✔
233
      return this;
1✔
234
    }
235

236
    public Builder setRetryOptions(RetryOptions retryOptions) {
237
      this.retryOptions = retryOptions;
1✔
238
      return this;
1✔
239
    }
240

241
    public Builder setCronSchedule(String cronSchedule) {
242
      this.cronSchedule = cronSchedule;
1✔
243
      return this;
1✔
244
    }
245

246
    /**
247
     * Specifies additional non-indexed information in result of list workflow. The type of value
248
     * can be any object that are serializable by {@link io.temporal.common.converter.DataConverter}
249
     */
250
    public Builder setMemo(Map<String, Object> memo) {
251
      this.memo = memo;
1✔
252
      return this;
1✔
253
    }
254

255
    /**
256
     * Specifies Search Attributes map {@code searchAttributes} that will be attached to the
257
     * Workflow. Search Attributes are additional indexed information attributed to workflow and
258
     * used for search and visibility.
259
     *
260
     * <p>The search attributes can be used in query of List/Scan/Count workflow APIs. The key and
261
     * its value type must be registered on Temporal server side.
262
     *
263
     * <p>Supported Java types of the value:
264
     *
265
     * <ul>
266
     *   <li>String
267
     *   <li>Long, Integer, Short, Byte
268
     *   <li>Boolean
269
     *   <li>Double
270
     *   <li>OffsetDateTime
271
     *   <li>{@link Collection} of the types above
272
     * </ul>
273
     *
274
     * @deprecated use {@link #setTypedSearchAttributes} instead.
275
     */
276
    // Workflow#upsertSearchAttributes docs needs to be kept in sync with this method
277
    @Deprecated
278
    public Builder setSearchAttributes(Map<String, ?> searchAttributes) {
279
      if (searchAttributes != null
1✔
280
          && !searchAttributes.isEmpty()
1✔
281
          && this.typedSearchAttributes != null) {
282
        throw new IllegalArgumentException(
×
283
            "Cannot have search attributes and typed search attributes");
284
      }
285
      this.searchAttributes = searchAttributes;
1✔
286
      return this;
1✔
287
    }
288

289
    /**
290
     * Specifies Search Attributes that will be attached to the Workflow. Search Attributes are
291
     * additional indexed information attributed to workflow and used for search and visibility.
292
     *
293
     * <p>The search attributes can be used in query of List/Scan/Count workflow APIs. The key and
294
     * its value type must be registered on Temporal server side.
295
     */
296
    public Builder setTypedSearchAttributes(SearchAttributes typedSearchAttributes) {
297
      if (typedSearchAttributes != null
1✔
298
          && searchAttributes != null
299
          && !searchAttributes.isEmpty()) {
×
300
        throw new IllegalArgumentException(
×
301
            "Cannot have typed search attributes and search attributes");
302
      }
303
      this.typedSearchAttributes = typedSearchAttributes;
1✔
304
      return this;
1✔
305
    }
306

307
    /**
308
     * This list of context propagators overrides the list specified on {@link
309
     * WorkflowClientOptions#getContextPropagators()}. <br>
310
     * This method is uncommon, the majority of users should just set {@link
311
     * WorkflowClientOptions#getContextPropagators()}
312
     *
313
     * @param contextPropagators specifies the list of overriding context propagators, {@code null}
314
     *     means no overriding.
315
     */
316
    public Builder setContextPropagators(@Nullable List<ContextPropagator> contextPropagators) {
317
      this.contextPropagators = contextPropagators;
1✔
318
      return this;
1✔
319
    }
320

321
    /**
322
     * If {@link WorkflowClient} is used to create a {@link WorkerFactory} that is
323
     *
324
     * <ul>
325
     *   <li>started
326
     *   <li>has a non-paused worker on the right task queue
327
     *   <li>has available workflow task executor slots
328
     * </ul>
329
     *
330
     * and such a {@link WorkflowClient} is used to start a workflow, then the first workflow task
331
     * could be dispatched on this local worker with the response to the start call if Server
332
     * supports it. This option can be used to disable this mechanism.
333
     *
334
     * @param disableEagerExecution if true, an eager local execution of the workflow task will
335
     *     never be requested even if it is possible.
336
     */
337
    public Builder setDisableEagerExecution(boolean disableEagerExecution) {
338
      this.disableEagerExecution = disableEagerExecution;
1✔
339
      return this;
1✔
340
    }
341

342
    public WorkflowOptions build() {
343
      return new WorkflowOptions(
1✔
344
          workflowId,
345
          workflowIdReusePolicy,
346
          workflowRunTimeout,
347
          workflowExecutionTimeout,
348
          workflowTaskTimeout,
349
          taskQueue,
350
          retryOptions,
351
          cronSchedule,
352
          memo,
353
          searchAttributes,
354
          typedSearchAttributes,
355
          contextPropagators,
356
          disableEagerExecution);
357
    }
358

359
    /**
360
     * Validates that all required properties are set and fills all other with default parameters.
361
     */
362
    public WorkflowOptions validateBuildWithDefaults() {
363
      return new WorkflowOptions(
1✔
364
          workflowId,
365
          workflowIdReusePolicy,
366
          workflowRunTimeout,
367
          workflowExecutionTimeout,
368
          workflowTaskTimeout,
369
          taskQueue,
370
          retryOptions,
371
          cronSchedule,
372
          memo,
373
          searchAttributes,
374
          typedSearchAttributes,
375
          contextPropagators,
376
          disableEagerExecution);
377
    }
378
  }
379

380
  private final String workflowId;
381

382
  private final WorkflowIdReusePolicy workflowIdReusePolicy;
383

384
  private final Duration workflowRunTimeout;
385

386
  private final Duration workflowExecutionTimeout;
387

388
  private final Duration workflowTaskTimeout;
389

390
  private final String taskQueue;
391

392
  private final RetryOptions retryOptions;
393

394
  private final String cronSchedule;
395

396
  private final Map<String, Object> memo;
397

398
  private final Map<String, ?> searchAttributes;
399

400
  private final SearchAttributes typedSearchAttributes;
401

402
  private final List<ContextPropagator> contextPropagators;
403

404
  private final boolean disableEagerExecution;
405

406
  private WorkflowOptions(
407
      String workflowId,
408
      WorkflowIdReusePolicy workflowIdReusePolicy,
409
      Duration workflowRunTimeout,
410
      Duration workflowExecutionTimeout,
411
      Duration workflowTaskTimeout,
412
      String taskQueue,
413
      RetryOptions retryOptions,
414
      String cronSchedule,
415
      Map<String, Object> memo,
416
      Map<String, ?> searchAttributes,
417
      SearchAttributes typedSearchAttributes,
418
      List<ContextPropagator> contextPropagators,
419
      boolean disableEagerExecution) {
1✔
420
    this.workflowId = workflowId;
1✔
421
    this.workflowIdReusePolicy = workflowIdReusePolicy;
1✔
422
    this.workflowRunTimeout = workflowRunTimeout;
1✔
423
    this.workflowExecutionTimeout = workflowExecutionTimeout;
1✔
424
    this.workflowTaskTimeout = workflowTaskTimeout;
1✔
425
    this.taskQueue = taskQueue;
1✔
426
    this.retryOptions = retryOptions;
1✔
427
    this.cronSchedule = cronSchedule;
1✔
428
    this.memo = memo;
1✔
429
    this.searchAttributes = searchAttributes;
1✔
430
    this.typedSearchAttributes = typedSearchAttributes;
1✔
431
    this.contextPropagators = contextPropagators;
1✔
432
    this.disableEagerExecution = disableEagerExecution;
1✔
433
  }
1✔
434

435
  public String getWorkflowId() {
436
    return workflowId;
1✔
437
  }
438

439
  public WorkflowIdReusePolicy getWorkflowIdReusePolicy() {
440
    return workflowIdReusePolicy;
1✔
441
  }
442

443
  public Duration getWorkflowRunTimeout() {
444
    return workflowRunTimeout;
1✔
445
  }
446

447
  public Duration getWorkflowExecutionTimeout() {
448
    return workflowExecutionTimeout;
1✔
449
  }
450

451
  public Duration getWorkflowTaskTimeout() {
452
    return workflowTaskTimeout;
1✔
453
  }
454

455
  public String getTaskQueue() {
456
    return taskQueue;
1✔
457
  }
458

459
  public RetryOptions getRetryOptions() {
460
    return retryOptions;
1✔
461
  }
462

463
  public String getCronSchedule() {
464
    return cronSchedule;
1✔
465
  }
466

467
  public Map<String, Object> getMemo() {
468
    return memo;
1✔
469
  }
470

471
  /**
472
   * @deprecated use {@link #getTypedSearchAttributes} instead.
473
   */
474
  @Deprecated
475
  public Map<String, ?> getSearchAttributes() {
476
    return searchAttributes;
1✔
477
  }
478

479
  public SearchAttributes getTypedSearchAttributes() {
480
    return typedSearchAttributes;
1✔
481
  }
482

483
  /**
484
   * @return the list of context propagators to use during this workflow. This list overrides the
485
   *     list specified on {@link WorkflowClientOptions#getContextPropagators()}, {@code null} means
486
   *     no overriding
487
   */
488
  public @Nullable List<ContextPropagator> getContextPropagators() {
489
    return contextPropagators;
1✔
490
  }
491

492
  public boolean isDisableEagerExecution() {
493
    return disableEagerExecution;
1✔
494
  }
495

496
  public Builder toBuilder() {
497
    return new Builder(this);
1✔
498
  }
499

500
  @Override
501
  public boolean equals(Object o) {
502
    if (this == o) return true;
1✔
503
    if (o == null || getClass() != o.getClass()) return false;
1✔
504
    WorkflowOptions that = (WorkflowOptions) o;
1✔
505
    return Objects.equal(workflowId, that.workflowId)
1✔
506
        && workflowIdReusePolicy == that.workflowIdReusePolicy
507
        && Objects.equal(workflowRunTimeout, that.workflowRunTimeout)
1✔
508
        && Objects.equal(workflowExecutionTimeout, that.workflowExecutionTimeout)
1✔
509
        && Objects.equal(workflowTaskTimeout, that.workflowTaskTimeout)
1✔
510
        && Objects.equal(taskQueue, that.taskQueue)
1✔
511
        && Objects.equal(retryOptions, that.retryOptions)
1✔
512
        && Objects.equal(cronSchedule, that.cronSchedule)
1✔
513
        && Objects.equal(memo, that.memo)
1✔
514
        && Objects.equal(searchAttributes, that.searchAttributes)
1✔
515
        && Objects.equal(typedSearchAttributes, that.typedSearchAttributes)
1✔
516
        && Objects.equal(contextPropagators, that.contextPropagators)
1✔
517
        && Objects.equal(disableEagerExecution, that.disableEagerExecution);
1✔
518
  }
519

520
  @Override
521
  public int hashCode() {
522
    return Objects.hashCode(
×
523
        workflowId,
524
        workflowIdReusePolicy,
525
        workflowRunTimeout,
526
        workflowExecutionTimeout,
527
        workflowTaskTimeout,
528
        taskQueue,
529
        retryOptions,
530
        cronSchedule,
531
        memo,
532
        searchAttributes,
533
        typedSearchAttributes,
534
        contextPropagators,
535
        disableEagerExecution);
×
536
  }
537

538
  @Override
539
  public String toString() {
540
    return "WorkflowOptions{"
×
541
        + "workflowId='"
542
        + workflowId
543
        + '\''
544
        + ", workflowIdReusePolicy="
545
        + workflowIdReusePolicy
546
        + ", workflowRunTimeout="
547
        + workflowRunTimeout
548
        + ", workflowExecutionTimeout="
549
        + workflowExecutionTimeout
550
        + ", workflowTaskTimeout="
551
        + workflowTaskTimeout
552
        + ", taskQueue='"
553
        + taskQueue
554
        + '\''
555
        + ", retryOptions="
556
        + retryOptions
557
        + ", cronSchedule='"
558
        + cronSchedule
559
        + '\''
560
        + ", memo="
561
        + memo
562
        + ", searchAttributes="
563
        + searchAttributes
564
        + ", typedSearchAttributes="
565
        + typedSearchAttributes
566
        + ", contextPropagators="
567
        + contextPropagators
568
        + ", disableEagerExecution="
569
        + disableEagerExecution
570
        + '}';
571
  }
572
}
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