• 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

77.69
/temporal-sdk/src/main/java/io/temporal/workflow/ChildWorkflowOptions.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.workflow;
22

23
import static io.temporal.internal.common.OptionsUtils.roundUpToSeconds;
24

25
import com.google.common.base.Objects;
26
import io.temporal.api.enums.v1.ParentClosePolicy;
27
import io.temporal.api.enums.v1.WorkflowIdReusePolicy;
28
import io.temporal.common.*;
29
import io.temporal.common.context.ContextPropagator;
30
import io.temporal.failure.CanceledFailure;
31
import io.temporal.failure.ChildWorkflowFailure;
32
import io.temporal.failure.TimeoutFailure;
33
import io.temporal.internal.common.OptionsUtils;
34
import java.time.Duration;
35
import java.util.List;
36
import java.util.Map;
37

38
public final class ChildWorkflowOptions {
39

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

44
  public static Builder newBuilder(ChildWorkflowOptions options) {
45
    return new Builder(options);
1✔
46
  }
47

48
  public static ChildWorkflowOptions getDefaultInstance() {
49
    return DEFAULT_INSTANCE;
×
50
  }
51

52
  private static final ChildWorkflowOptions DEFAULT_INSTANCE;
53

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

58
  public static final class Builder {
59

60
    private String namespace;
61
    private String workflowId;
62
    private WorkflowIdReusePolicy workflowIdReusePolicy;
63
    private Duration workflowRunTimeout;
64
    private Duration workflowExecutionTimeout;
65
    private Duration workflowTaskTimeout;
66
    private String taskQueue;
67
    private RetryOptions retryOptions;
68
    private String cronSchedule;
69
    private ParentClosePolicy parentClosePolicy;
70
    private Map<String, Object> memo;
71
    private Map<String, Object> searchAttributes;
72
    private SearchAttributes typedSearchAttributes;
73
    private List<ContextPropagator> contextPropagators;
74
    private ChildWorkflowCancellationType cancellationType;
75
    private VersioningIntent versioningIntent;
76

77
    private Builder() {}
78

79
    private Builder(ChildWorkflowOptions options) {
1✔
80
      if (options == null) {
1✔
81
        return;
1✔
82
      }
83
      this.namespace = options.getNamespace();
1✔
84
      this.workflowId = options.getWorkflowId();
1✔
85
      this.workflowIdReusePolicy = options.getWorkflowIdReusePolicy();
1✔
86
      this.workflowRunTimeout = options.getWorkflowRunTimeout();
1✔
87
      this.workflowExecutionTimeout = options.getWorkflowExecutionTimeout();
1✔
88
      this.workflowTaskTimeout = options.getWorkflowTaskTimeout();
1✔
89
      this.taskQueue = options.getTaskQueue();
1✔
90
      this.retryOptions = options.getRetryOptions();
1✔
91
      this.cronSchedule = options.getCronSchedule();
1✔
92
      this.parentClosePolicy = options.getParentClosePolicy();
1✔
93
      this.memo = options.getMemo();
1✔
94
      this.searchAttributes = options.getSearchAttributes();
1✔
95
      this.typedSearchAttributes = options.getTypedSearchAttributes();
1✔
96
      this.contextPropagators = options.getContextPropagators();
1✔
97
      this.cancellationType = options.getCancellationType();
1✔
98
      this.versioningIntent = options.getVersioningIntent();
1✔
99
    }
1✔
100

101
    /**
102
     * Specify namespace in which workflow should be started.
103
     *
104
     * <p>TODO: Resolve conflict with WorkflowClient namespace.
105
     */
106
    public Builder setNamespace(String namespace) {
107
      this.namespace = namespace;
×
108
      return this;
×
109
    }
110

111
    /**
112
     * Workflow id to use when starting. If not specified a UUID is generated. Note that it is
113
     * dangerous as in case of client side retries no deduplication will happen based on the
114
     * generated id. So prefer assigning business meaningful ids if possible.
115
     */
116
    public Builder setWorkflowId(String workflowId) {
117
      this.workflowId = workflowId;
1✔
118
      return this;
1✔
119
    }
120

121
    /**
122
     * Specifies server behavior if a completed workflow with the same id exists. Note that under no
123
     * conditions Temporal allows two workflows with the same namespace and workflow id run
124
     * simultaneously.
125
     * <li>
126
     *
127
     *     <ul>
128
     *       AllowDuplicateFailedOnly is a default value. It means that workflow can start if
129
     *       previous run failed or was canceled or terminated.
130
     * </ul>
131
     *
132
     * <ul>
133
     *   AllowDuplicate allows new run independently of the previous run closure status.
134
     * </ul>
135
     *
136
     * <ul>
137
     *   RejectDuplicate doesn't allow new run independently of the previous run closure status.
138
     * </ul>
139
     */
140
    public Builder setWorkflowIdReusePolicy(WorkflowIdReusePolicy workflowIdReusePolicy) {
141
      this.workflowIdReusePolicy = workflowIdReusePolicy;
1✔
142
      return this;
1✔
143
    }
144

145
    /**
146
     * The time after which child workflow run is automatically terminated by Temporal service with
147
     * CHILD_WORKFLOW_EXECUTION_TIMED_OUT status. <br>
148
     * Parent workflow receives {@link ChildWorkflowFailure} exception with {@link TimeoutFailure}
149
     * cause from the child's {@link Promise} if this happens.
150
     *
151
     * <p>When a workflow reaches Workflow Run Timeout, it can't make any progress after that. Do
152
     * not rely on this timeout in workflow implementation or business logic. This timeout is not
153
     * designed to be handled in workflow code to perform any logic in case of timeout. Consider
154
     * using workflow timers instead.
155
     *
156
     * <p>If you catch yourself setting this timeout to very small values, you're likely using it
157
     * wrong.
158
     *
159
     * <p>Example: If Workflow Run Timeout is 30 seconds and the network was unavailable for 1
160
     * minute, workflows that were scheduled before the network blip will never have a chance to
161
     * make progress or react, and will be terminated. <br>
162
     * A timer that is scheduled in the workflow code using {@link Workflow#newTimer(Duration)} will
163
     * handle this situation gracefully. A workflow with such a timer will start after the network
164
     * blip. If it started before the network blip and the timer fires during the network blip, it
165
     * will get delivered after connectivity is restored and the workflow will be able to resume.
166
     */
167
    public Builder setWorkflowRunTimeout(Duration workflowRunTimeout) {
168
      this.workflowRunTimeout = workflowRunTimeout;
1✔
169
      return this;
1✔
170
    }
171

172
    /**
173
     * The time after which child workflow execution (which includes run retries and continue as
174
     * new) is automatically terminated by Temporal service with WORKFLOW_EXECUTION_TIMED_OUT
175
     * status. <br>
176
     * Parent workflow receives {@link ChildWorkflowFailure} exception with {@link TimeoutFailure}
177
     * cause from the child's {@link Promise} if this happens.
178
     *
179
     * <p>When a workflow reaches Workflow Execution Timeout, it can't make any progress after that.
180
     * Do not rely on this timeout in workflow implementation or business logic. This timeout is not
181
     * designed to be handled in workflow code to perform any logic in case of timeout. Consider
182
     * using workflow timers instead.
183
     *
184
     * <p>If you catch yourself setting this timeout to very small values, you're likely using it
185
     * wrong.
186
     *
187
     * <p>Example: If Workflow Execution Timeout is 30 seconds and the network was unavailable for 1
188
     * minute, workflows that were scheduled before the network blip will never have a chance to
189
     * make progress or react, and will be terminated. <br>
190
     * A timer that is scheduled in the workflow code using {@link Workflow#newTimer(Duration)} will
191
     * handle this situation gracefully. A workflow with such a timer will start after the network
192
     * blip. If it started before the network blip and the timer fires during the network blip, it
193
     * will get delivered after connectivity is restored and the workflow will be able to resume.
194
     */
195
    public Builder setWorkflowExecutionTimeout(Duration workflowExecutionTimeout) {
196
      this.workflowExecutionTimeout = workflowExecutionTimeout;
1✔
197
      return this;
1✔
198
    }
199

200
    /**
201
     * Maximum execution time of a single workflow task. Default is 10 seconds. Maximum accepted
202
     * value is 60 seconds.
203
     */
204
    public Builder setWorkflowTaskTimeout(Duration workflowTaskTimeout) {
205
      if (roundUpToSeconds(workflowTaskTimeout) > 60) {
1✔
206
        throw new IllegalArgumentException(
×
207
            "WorkflowTaskTimeout over one minute: " + workflowTaskTimeout);
208
      }
209
      this.workflowTaskTimeout = workflowTaskTimeout;
1✔
210
      return this;
1✔
211
    }
212

213
    /**
214
     * Task queue to use for workflow tasks. It should match a task queue specified when creating a
215
     * {@link io.temporal.worker.Worker} that hosts the workflow code.
216
     */
217
    public Builder setTaskQueue(String taskQueue) {
218
      this.taskQueue = taskQueue;
1✔
219
      return this;
1✔
220
    }
221

222
    /**
223
     * RetryOptions that define how child workflow is retried in case of failure. Default is null
224
     * which is no reties.
225
     */
226
    public Builder setRetryOptions(RetryOptions retryOptions) {
227
      this.retryOptions = retryOptions;
1✔
228
      return this;
1✔
229
    }
230

231
    public Builder setCronSchedule(String cronSchedule) {
232
      this.cronSchedule = cronSchedule;
1✔
233
      return this;
1✔
234
    }
235

236
    /** Specifies how this workflow reacts to the death of the parent workflow. */
237
    public Builder setParentClosePolicy(ParentClosePolicy parentClosePolicy) {
238
      this.parentClosePolicy = parentClosePolicy;
1✔
239
      return this;
1✔
240
    }
241

242
    /** Specifies additional non-indexed information in result of list workflow. */
243
    public Builder setMemo(Map<String, Object> memo) {
244
      this.memo = memo;
1✔
245
      return this;
1✔
246
    }
247

248
    /**
249
     * Specifies additional indexed information in result of list workflow.
250
     *
251
     * @deprecated use {@link #setTypedSearchAttributes} instead.
252
     */
253
    @Deprecated
254
    public Builder setSearchAttributes(Map<String, Object> searchAttributes) {
255
      if (searchAttributes != null
1✔
256
          && !searchAttributes.isEmpty()
1✔
257
          && this.typedSearchAttributes != null) {
258
        throw new IllegalArgumentException(
×
259
            "Cannot have search attributes and typed search attributes");
260
      }
261
      this.searchAttributes = searchAttributes;
1✔
262
      return this;
1✔
263
    }
264

265
    /** Specifies additional indexed information in result of list workflow. */
266
    public Builder setTypedSearchAttributes(SearchAttributes typedSearchAttributes) {
267
      if (typedSearchAttributes != null
1✔
268
          && searchAttributes != null
269
          && !searchAttributes.isEmpty()) {
×
270
        throw new IllegalArgumentException(
×
271
            "Cannot have typed search attributes and search attributes");
272
      }
273
      this.typedSearchAttributes = typedSearchAttributes;
1✔
274
      return this;
1✔
275
    }
276

277
    /** Specifies the list of context propagators to use during this workflow. */
278
    public Builder setContextPropagators(List<ContextPropagator> contextPropagators) {
279
      this.contextPropagators = contextPropagators;
×
280
      return this;
×
281
    }
282

283
    /**
284
     * In case of a child workflow cancellation it fails with a {@link CanceledFailure}. The type
285
     * defines at which point the exception is thrown.
286
     */
287
    public Builder setCancellationType(ChildWorkflowCancellationType cancellationType) {
288
      this.cancellationType = cancellationType;
1✔
289
      return this;
1✔
290
    }
291

292
    public Builder setMethodRetry(MethodRetry r) {
293
      retryOptions = RetryOptions.merge(r, retryOptions);
1✔
294
      return this;
1✔
295
    }
296

297
    public Builder setCronSchedule(CronSchedule c) {
298
      String cronAnnotation = c == null ? "" : c.value();
1✔
299
      cronSchedule = OptionsUtils.merge(cronAnnotation, cronSchedule, String.class);
1✔
300
      return this;
1✔
301
    }
302

303
    /**
304
     * Specifies whether this child workflow should run on a worker with a compatible Build Id or
305
     * not. See the variants of {@link VersioningIntent}.
306
     */
307
    public Builder setVersioningIntent(VersioningIntent versioningIntent) {
308
      this.versioningIntent = versioningIntent;
×
309
      return this;
×
310
    }
311

312
    public ChildWorkflowOptions build() {
313
      return new ChildWorkflowOptions(
1✔
314
          namespace,
315
          workflowId,
316
          workflowIdReusePolicy,
317
          workflowRunTimeout,
318
          workflowExecutionTimeout,
319
          workflowTaskTimeout,
320
          taskQueue,
321
          retryOptions,
322
          cronSchedule,
323
          parentClosePolicy,
324
          memo,
325
          searchAttributes,
326
          typedSearchAttributes,
327
          contextPropagators,
328
          cancellationType,
329
          versioningIntent);
330
    }
331

332
    public ChildWorkflowOptions validateAndBuildWithDefaults() {
333
      return new ChildWorkflowOptions(
1✔
334
          namespace,
335
          workflowId,
336
          workflowIdReusePolicy,
337
          workflowRunTimeout,
338
          workflowExecutionTimeout,
339
          workflowTaskTimeout,
340
          taskQueue,
341
          retryOptions,
342
          cronSchedule,
343
          parentClosePolicy,
344
          memo,
345
          searchAttributes,
346
          typedSearchAttributes,
347
          contextPropagators,
348
          cancellationType == null
1✔
349
              ? ChildWorkflowCancellationType.WAIT_CANCELLATION_COMPLETED
1✔
350
              : cancellationType,
1✔
351
          versioningIntent == null
1✔
352
              ? VersioningIntent.VERSIONING_INTENT_UNSPECIFIED
1✔
353
              : versioningIntent);
1✔
354
    }
355
  }
356

357
  private final String namespace;
358
  private final String workflowId;
359
  private final WorkflowIdReusePolicy workflowIdReusePolicy;
360
  private final Duration workflowRunTimeout;
361
  private final Duration workflowExecutionTimeout;
362
  private final Duration workflowTaskTimeout;
363
  private final String taskQueue;
364
  private final RetryOptions retryOptions;
365
  private final String cronSchedule;
366
  private final ParentClosePolicy parentClosePolicy;
367
  private final Map<String, Object> memo;
368
  private final Map<String, Object> searchAttributes;
369
  private final SearchAttributes typedSearchAttributes;
370
  private final List<ContextPropagator> contextPropagators;
371
  private final ChildWorkflowCancellationType cancellationType;
372
  private final VersioningIntent versioningIntent;
373

374
  private ChildWorkflowOptions(
375
      String namespace,
376
      String workflowId,
377
      WorkflowIdReusePolicy workflowIdReusePolicy,
378
      Duration workflowRunTimeout,
379
      Duration workflowExecutionTimeout,
380
      Duration workflowTaskTimeout,
381
      String taskQueue,
382
      RetryOptions retryOptions,
383
      String cronSchedule,
384
      ParentClosePolicy parentClosePolicy,
385
      Map<String, Object> memo,
386
      Map<String, Object> searchAttributes,
387
      SearchAttributes typedSearchAttributes,
388
      List<ContextPropagator> contextPropagators,
389
      ChildWorkflowCancellationType cancellationType,
390
      VersioningIntent versioningIntent) {
1✔
391
    this.namespace = namespace;
1✔
392
    this.workflowId = workflowId;
1✔
393
    this.workflowIdReusePolicy = workflowIdReusePolicy;
1✔
394
    this.workflowRunTimeout = workflowRunTimeout;
1✔
395
    this.workflowExecutionTimeout = workflowExecutionTimeout;
1✔
396
    this.workflowTaskTimeout = workflowTaskTimeout;
1✔
397
    this.taskQueue = taskQueue;
1✔
398
    this.retryOptions = retryOptions;
1✔
399
    this.cronSchedule = cronSchedule;
1✔
400
    this.parentClosePolicy = parentClosePolicy;
1✔
401
    this.memo = memo;
1✔
402
    this.searchAttributes = searchAttributes;
1✔
403
    this.typedSearchAttributes = typedSearchAttributes;
1✔
404
    this.contextPropagators = contextPropagators;
1✔
405
    this.cancellationType = cancellationType;
1✔
406
    this.versioningIntent = versioningIntent;
1✔
407
  }
1✔
408

409
  public String getNamespace() {
410
    return namespace;
1✔
411
  }
412

413
  public String getWorkflowId() {
414
    return workflowId;
1✔
415
  }
416

417
  public WorkflowIdReusePolicy getWorkflowIdReusePolicy() {
418
    return workflowIdReusePolicy;
1✔
419
  }
420

421
  public Duration getWorkflowRunTimeout() {
422
    return workflowRunTimeout;
1✔
423
  }
424

425
  public Duration getWorkflowExecutionTimeout() {
426
    return workflowExecutionTimeout;
1✔
427
  }
428

429
  public Duration getWorkflowTaskTimeout() {
430
    return workflowTaskTimeout;
1✔
431
  }
432

433
  public String getTaskQueue() {
434
    return taskQueue;
1✔
435
  }
436

437
  public RetryOptions getRetryOptions() {
438
    return retryOptions;
1✔
439
  }
440

441
  public String getCronSchedule() {
442
    return cronSchedule;
1✔
443
  }
444

445
  public ParentClosePolicy getParentClosePolicy() {
446
    return parentClosePolicy;
1✔
447
  }
448

449
  public Map<String, Object> getMemo() {
450
    return memo;
1✔
451
  }
452

453
  /**
454
   * @deprecated use {@link #getTypedSearchAttributes} instead.
455
   */
456
  @Deprecated
457
  public Map<String, Object> getSearchAttributes() {
458
    return searchAttributes;
1✔
459
  }
460

461
  public SearchAttributes getTypedSearchAttributes() {
462
    return typedSearchAttributes;
1✔
463
  }
464

465
  public List<ContextPropagator> getContextPropagators() {
466
    return contextPropagators;
1✔
467
  }
468

469
  public ChildWorkflowCancellationType getCancellationType() {
470
    return cancellationType;
1✔
471
  }
472

473
  public VersioningIntent getVersioningIntent() {
474
    return versioningIntent;
1✔
475
  }
476

477
  public Builder toBuilder() {
478
    return new Builder(this);
×
479
  }
480

481
  @Override
482
  public boolean equals(Object o) {
483
    if (this == o) return true;
×
484
    if (o == null || getClass() != o.getClass()) return false;
×
485
    ChildWorkflowOptions that = (ChildWorkflowOptions) o;
×
486
    return Objects.equal(namespace, that.namespace)
×
487
        && Objects.equal(workflowId, that.workflowId)
×
488
        && workflowIdReusePolicy == that.workflowIdReusePolicy
489
        && Objects.equal(workflowRunTimeout, that.workflowRunTimeout)
×
490
        && Objects.equal(workflowExecutionTimeout, that.workflowExecutionTimeout)
×
491
        && Objects.equal(workflowTaskTimeout, that.workflowTaskTimeout)
×
492
        && Objects.equal(taskQueue, that.taskQueue)
×
493
        && Objects.equal(retryOptions, that.retryOptions)
×
494
        && Objects.equal(cronSchedule, that.cronSchedule)
×
495
        && parentClosePolicy == that.parentClosePolicy
496
        && Objects.equal(memo, that.memo)
×
497
        && Objects.equal(searchAttributes, that.searchAttributes)
×
498
        && Objects.equal(typedSearchAttributes, that.typedSearchAttributes)
×
499
        && Objects.equal(contextPropagators, that.contextPropagators)
×
500
        && cancellationType == that.cancellationType
501
        && versioningIntent == that.versioningIntent;
502
  }
503

504
  @Override
505
  public int hashCode() {
506
    return Objects.hashCode(
×
507
        namespace,
508
        workflowId,
509
        workflowIdReusePolicy,
510
        workflowRunTimeout,
511
        workflowExecutionTimeout,
512
        workflowTaskTimeout,
513
        taskQueue,
514
        retryOptions,
515
        cronSchedule,
516
        parentClosePolicy,
517
        memo,
518
        searchAttributes,
519
        typedSearchAttributes,
520
        contextPropagators,
521
        cancellationType,
522
        versioningIntent);
523
  }
524

525
  @Override
526
  public String toString() {
527
    return "ChildWorkflowOptions{"
×
528
        + "namespace='"
529
        + namespace
530
        + '\''
531
        + ", workflowId='"
532
        + workflowId
533
        + '\''
534
        + ", workflowIdReusePolicy="
535
        + workflowIdReusePolicy
536
        + ", workflowRunTimeout="
537
        + workflowRunTimeout
538
        + ", workflowExecutionTimeout="
539
        + workflowExecutionTimeout
540
        + ", workflowTaskTimeout="
541
        + workflowTaskTimeout
542
        + ", taskQueue='"
543
        + taskQueue
544
        + '\''
545
        + ", retryOptions="
546
        + retryOptions
547
        + ", cronSchedule='"
548
        + cronSchedule
549
        + '\''
550
        + ", parentClosePolicy="
551
        + parentClosePolicy
552
        + ", memo="
553
        + memo
554
        + ", searchAttributes="
555
        + searchAttributes
556
        + ", typedSearchAttributes="
557
        + typedSearchAttributes
558
        + ", contextPropagators="
559
        + contextPropagators
560
        + ", cancellationType="
561
        + cancellationType
562
        + ", versioningIntent="
563
        + versioningIntent
564
        + '}';
565
  }
566
}
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