• 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

73.12
/temporal-sdk/src/main/java/io/temporal/workflow/Workflow.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 com.uber.m3.tally.Scope;
24
import io.temporal.activity.ActivityOptions;
25
import io.temporal.activity.LocalActivityOptions;
26
import io.temporal.api.common.v1.WorkflowExecution;
27
import io.temporal.common.RetryOptions;
28
import io.temporal.common.SearchAttributeUpdate;
29
import io.temporal.common.SearchAttributes;
30
import io.temporal.common.converter.DataConverter;
31
import io.temporal.failure.ActivityFailure;
32
import io.temporal.failure.CanceledFailure;
33
import io.temporal.failure.ChildWorkflowFailure;
34
import io.temporal.internal.sync.WorkflowInternal;
35
import io.temporal.serviceclient.WorkflowServiceStubsOptions;
36
import io.temporal.worker.WorkerFactoryOptions;
37
import io.temporal.worker.WorkflowImplementationOptions;
38
import io.temporal.workflow.Functions.Func;
39
import io.temporal.workflow.unsafe.WorkflowUnsafe;
40
import java.lang.reflect.Type;
41
import java.time.Duration;
42
import java.time.OffsetDateTime;
43
import java.util.*;
44
import java.util.function.BiPredicate;
45
import java.util.function.Supplier;
46
import javax.annotation.Nonnull;
47
import javax.annotation.Nullable;
48
import org.slf4j.Logger;
49

50
/**
51
 * This class contains methods exposing Temporal API for Workflows, like
52
 *
53
 * <ul>
54
 *   <li>Creation and scheduling of activities, child workflows, external workflows, continue-as-new
55
 *       runs
56
 *   <li>Operations over workflow elements, like Side Effects, Timers, Versions, {@link
57
 *       CancellationScope}
58
 *   <li>Accessing and updating of the workflow data, like {@link WorkflowInfo}, Memos and Search
59
 *       Attributes
60
 *   <li>Deterministic implementation of popular non-deterministic API working with time, logging
61
 *       and generation of random values
62
 * </ul>
63
 *
64
 * Methods of this class are intended to be called from a workflow method only until explicitly
65
 * stated otherwise on the specific method's javadoc.
66
 *
67
 * <p>For an overview of Temporal JavaSDK Workflows, see {@link io.temporal.workflow}
68
 *
69
 * <p>For methods providing Temporal Workflow alternatives to threading and asynchronous
70
 * invocations, see {@link Async}
71
 *
72
 * @see io.temporal.workflow
73
 */
74
public final class Workflow {
75
  public static final int DEFAULT_VERSION = WorkflowInternal.DEFAULT_VERSION;
76

77
  /**
78
   * Creates client stub to activities that implement given interface. `
79
   *
80
   * @param activityInterface interface type implemented by activities
81
   */
82
  public static <T> T newActivityStub(Class<T> activityInterface) {
83
    return WorkflowInternal.newActivityStub(activityInterface, null, null);
1✔
84
  }
85

86
  /**
87
   * Creates client stub to activities that implement given interface
88
   *
89
   * @param activityInterface interface type implemented by activities.
90
   * @param options options that together with the properties of {@link
91
   *     io.temporal.activity.ActivityMethod} specify the activity invocation parameters
92
   */
93
  public static <T> T newActivityStub(Class<T> activityInterface, ActivityOptions options) {
94
    return WorkflowInternal.newActivityStub(activityInterface, options, null);
1✔
95
  }
96

97
  /**
98
   * Creates client stub to activities that implement given interface.
99
   *
100
   * @param activityInterface interface type implemented by activities
101
   * @param options options that together with the properties of {@link
102
   *     io.temporal.activity.ActivityMethod} specify the activity invocation parameters
103
   * @param activityMethodOptions activity method-specific invocation parameters
104
   */
105
  public static <T> T newActivityStub(
106
      Class<T> activityInterface,
107
      ActivityOptions options,
108
      Map<String, ActivityOptions> activityMethodOptions) {
109
    return WorkflowInternal.newActivityStub(activityInterface, options, activityMethodOptions);
×
110
  }
111

112
  /**
113
   * Creates non typed client stub to activities. Allows executing activities by their string name.
114
   *
115
   * @param options specify the activity invocation parameters.
116
   */
117
  public static ActivityStub newUntypedActivityStub(ActivityOptions options) {
118
    return WorkflowInternal.newUntypedActivityStub(options);
1✔
119
  }
120

121
  /**
122
   * Creates client stub to local activities that implement given interface.
123
   *
124
   * @param activityInterface interface type implemented by activities
125
   */
126
  public static <T> T newLocalActivityStub(Class<T> activityInterface) {
127
    return WorkflowInternal.newLocalActivityStub(activityInterface, null, null);
1✔
128
  }
129

130
  /**
131
   * Creates client stub to local activities that implement given interface. A local activity is
132
   * similar to a regular activity, but with some key differences: 1. Local activity is scheduled
133
   * and run by the workflow worker locally. 2. Local activity does not need Temporal server to
134
   * schedule activity task and does not rely on activity worker. 3. Local activity is for short
135
   * living activities (usually finishes within seconds). 4. Local activity cannot heartbeat.
136
   *
137
   * @param activityInterface interface type implemented by activities
138
   * @param options options that together with the properties of {@link
139
   *     io.temporal.activity.ActivityMethod} specify the activity invocation parameters.
140
   */
141
  public static <T> T newLocalActivityStub(
142
      Class<T> activityInterface, LocalActivityOptions options) {
143
    return WorkflowInternal.newLocalActivityStub(activityInterface, options, null);
1✔
144
  }
145

146
  /**
147
   * Creates client stub to local activities that implement given interface.
148
   *
149
   * @param activityInterface interface type implemented by activities
150
   * @param options options that together with the properties of {@link
151
   *     io.temporal.activity.ActivityMethod} specify the activity invocation parameters
152
   * @param activityMethodOptions activity method-specific invocation parameters
153
   */
154
  public static <T> T newLocalActivityStub(
155
      Class<T> activityInterface,
156
      LocalActivityOptions options,
157
      Map<String, LocalActivityOptions> activityMethodOptions) {
158
    return WorkflowInternal.newLocalActivityStub(activityInterface, options, activityMethodOptions);
×
159
  }
160

161
  /**
162
   * Creates non typed client stub to local activities. Allows executing activities by their string
163
   * name.
164
   *
165
   * @param options specify the local activity invocation parameters.
166
   */
167
  public static ActivityStub newUntypedLocalActivityStub(LocalActivityOptions options) {
168
    return WorkflowInternal.newUntypedLocalActivityStub(options);
1✔
169
  }
170

171
  /**
172
   * Creates client stub that can be used to start a child workflow that implements the given
173
   * interface using parent options. Use {@link #newExternalWorkflowStub(Class, String)} to get a
174
   * stub to signal a workflow without starting it.
175
   *
176
   * @param workflowInterface interface type implemented by activities
177
   */
178
  public static <T> T newChildWorkflowStub(Class<T> workflowInterface) {
179
    return WorkflowInternal.newChildWorkflowStub(workflowInterface, null);
1✔
180
  }
181

182
  /**
183
   * Creates client stub that can be used to start a child workflow that implements given interface.
184
   * Use {@link #newExternalWorkflowStub(Class, String)} to get a stub to signal a workflow without
185
   * starting it.
186
   *
187
   * @param workflowInterface interface type implemented by activities
188
   * @param options options passed to the child workflow.
189
   */
190
  public static <T> T newChildWorkflowStub(
191
      Class<T> workflowInterface, ChildWorkflowOptions options) {
192
    return WorkflowInternal.newChildWorkflowStub(workflowInterface, options);
1✔
193
  }
194

195
  /**
196
   * Creates client stub that can be used to communicate to an existing workflow execution.
197
   *
198
   * @param workflowInterface interface type implemented by activities
199
   * @param workflowId id of the workflow to communicate with.
200
   */
201
  public static <R> R newExternalWorkflowStub(
202
      Class<? extends R> workflowInterface, String workflowId) {
203
    WorkflowExecution execution = WorkflowExecution.newBuilder().setWorkflowId(workflowId).build();
1✔
204
    return WorkflowInternal.newExternalWorkflowStub(workflowInterface, execution);
1✔
205
  }
206

207
  /**
208
   * Creates client stub that can be used to communicate to an existing workflow execution.
209
   *
210
   * @param workflowInterface interface type implemented by activities
211
   * @param execution execution of the workflow to communicate with.
212
   */
213
  public static <R> R newExternalWorkflowStub(
214
      Class<? extends R> workflowInterface, WorkflowExecution execution) {
215
    return WorkflowInternal.newExternalWorkflowStub(workflowInterface, execution);
1✔
216
  }
217

218
  /**
219
   * Extracts workflow execution from a stub created through {@link #newChildWorkflowStub(Class,
220
   * ChildWorkflowOptions)} or {@link #newExternalWorkflowStub(Class, String)}. Wrapped in a Promise
221
   * as child workflow start is asynchronous.
222
   */
223
  public static Promise<WorkflowExecution> getWorkflowExecution(Object childWorkflowStub) {
224
    return WorkflowInternal.getWorkflowExecution(childWorkflowStub);
1✔
225
  }
226

227
  /**
228
   * Creates untyped client stub that can be used to start and signal a child workflow.
229
   *
230
   * @param workflowType name of the workflow type to start.
231
   * @param options options passed to the child workflow.
232
   */
233
  public static ChildWorkflowStub newUntypedChildWorkflowStub(
234
      String workflowType, ChildWorkflowOptions options) {
235
    return WorkflowInternal.newUntypedChildWorkflowStub(workflowType, options);
1✔
236
  }
237

238
  /**
239
   * Creates untyped client stub that can be used to start and signal a child workflow. All options
240
   * are inherited from the parent.
241
   *
242
   * @param workflowType name of the workflow type to start.
243
   */
244
  public static ChildWorkflowStub newUntypedChildWorkflowStub(String workflowType) {
245
    return WorkflowInternal.newUntypedChildWorkflowStub(workflowType, null);
1✔
246
  }
247

248
  /**
249
   * Creates untyped client stub that can be used to signal or cancel an existing workflow
250
   * execution.
251
   *
252
   * @param execution execution of the workflow to communicate with.
253
   */
254
  public static ExternalWorkflowStub newUntypedExternalWorkflowStub(WorkflowExecution execution) {
255
    return WorkflowInternal.newUntypedExternalWorkflowStub(execution);
1✔
256
  }
257

258
  /**
259
   * Creates untyped client stub that can be used to signal or cancel an existing workflow
260
   * execution.
261
   *
262
   * @param workflowId id of the workflow to communicate with.
263
   */
264
  public static ExternalWorkflowStub newUntypedExternalWorkflowStub(String workflowId) {
265
    WorkflowExecution execution = WorkflowExecution.newBuilder().setWorkflowId(workflowId).build();
1✔
266
    return Workflow.newUntypedExternalWorkflowStub(execution);
1✔
267
  }
268

269
  /**
270
   * Creates a client stub that can be used to continue this workflow as a new run.
271
   *
272
   * @param workflowInterface an interface type implemented by the next run of the workflow
273
   */
274
  public static <T> T newContinueAsNewStub(
275
      Class<T> workflowInterface, ContinueAsNewOptions options) {
276
    return WorkflowInternal.newContinueAsNewStub(workflowInterface, options);
1✔
277
  }
278

279
  /**
280
   * Creates a client stub that can be used to continue this workflow as a new run.
281
   *
282
   * @param workflowInterface an interface type implemented by the next run of the workflow
283
   */
284
  public static <T> T newContinueAsNewStub(Class<T> workflowInterface) {
285
    return WorkflowInternal.newContinueAsNewStub(workflowInterface, null);
1✔
286
  }
287

288
  /**
289
   * Continues the current workflow execution as a new run with the same options.
290
   *
291
   * @param args arguments of the next run.
292
   * @see #newContinueAsNewStub(Class)
293
   */
294
  public static void continueAsNew(Object... args) {
295
    Workflow.continueAsNew(null, args);
×
296
  }
×
297

298
  /**
299
   * Continues the current workflow execution as a new run with the same workflowType and overridden
300
   * {@code options}.
301
   *
302
   * @param options option overrides for the next run, can contain null if no overrides are needed
303
   * @param args arguments of the next run.
304
   * @see #newContinueAsNewStub(Class, ContinueAsNewOptions)
305
   */
306
  public static void continueAsNew(@Nullable ContinueAsNewOptions options, Object... args) {
307
    Workflow.continueAsNew(null, options, args);
×
308
  }
×
309

310
  /**
311
   * Continues the current workflow execution as a new run possibly overriding the workflow type and
312
   * options.
313
   *
314
   * @param workflowType workflow type override for the next run, can contain null if no override is
315
   *     needed
316
   * @param options option overrides for the next run, can contain null if no overrides are needed
317
   * @param args arguments of the next run.
318
   * @see #newContinueAsNewStub(Class)
319
   * @deprecated use {@link #continueAsNew(String, ContinueAsNewOptions, Object...)}
320
   */
321
  @Deprecated
322
  public static void continueAsNew(
323
      Optional<String> workflowType, Optional<ContinueAsNewOptions> options, Object... args) {
324
    WorkflowInternal.continueAsNew(workflowType.orElse(null), options.orElse(null), args);
×
325
  }
×
326

327
  /**
328
   * Continues the current workflow execution as a new run possibly overriding the workflow type and
329
   * options.
330
   *
331
   * @param workflowType workflow type override for the next run, can be null of no override is
332
   *     needed
333
   * @param options option overrides for the next run, can be null if no overrides are needed
334
   * @param args arguments of the next run.
335
   * @see #newContinueAsNewStub(Class)
336
   */
337
  public static void continueAsNew(
338
      @Nullable String workflowType, @Nullable ContinueAsNewOptions options, Object... args) {
339
    WorkflowInternal.continueAsNew(workflowType, options, args);
×
340
  }
×
341

342
  public static WorkflowInfo getInfo() {
343
    return WorkflowInternal.getWorkflowInfo();
1✔
344
  }
345

346
  /**
347
   * Extract deserialized Memo associated with given key
348
   *
349
   * @param key memo key
350
   * @param valueClass Java class to deserialize into
351
   * @return deserialized Memo or null if the key is not present in the memo
352
   */
353
  public static <T> Object getMemo(String key, Class<T> valueClass) {
354
    return getMemo(key, valueClass, valueClass);
1✔
355
  }
356

357
  /**
358
   * Extract Memo associated with the given key and deserialized into an object of generic type as
359
   * is done here: {@link DataConverter#fromPayloads(int, java.util.Optional, java.lang.Class,
360
   * java.lang.reflect.Type)} Ex: To deserialize into {@code HashMap<String, Integer>} {@code
361
   * Workflow.getMemo(key, Map.class, new TypeToken<HashMap<String, Integer>>() {}.getType())}
362
   *
363
   * @param key memo key
364
   * @param valueClass Java class to deserialize into
365
   * @param genericType type parameter for the generic class
366
   * @return deserialized Memo or null if the key is not present in the memo
367
   */
368
  public static <T> T getMemo(String key, Class<T> valueClass, Type genericType) {
369
    return WorkflowInternal.getMemo(key, valueClass, genericType);
1✔
370
  }
371

372
  /**
373
   * Wraps the Runnable method argument in a {@link CancellationScope}. The {@link
374
   * CancellationScope#run()} calls {@link Runnable#run()} on the wrapped Runnable. The returned
375
   * CancellationScope can be used to cancel the wrapped code. The cancellation semantic depends on
376
   * the operation the code is blocked on. For example activity or child workflow is first canceled
377
   * then throws a {@link CanceledFailure}. The same applies for {@link Workflow#sleep(long)}
378
   * operation. When an activity or a child workflow is invoked asynchronously then they get
379
   * canceled and a {@link Promise} that contains their result will throw {@link CanceledFailure}
380
   * when {@link Promise#get()} is called.
381
   *
382
   * <p>The new cancellation scope {@link CancellationScope#current()} is linked to the parent one.
383
   * If the parent one is canceled then all the children scopes are wrapped within a root
384
   * cancellation scope which gets canceled when a workflow is canceled through the Temporal
385
   * CancelWorkflowExecution API. To perform cleanup operations that require blocking after the
386
   * current scope is canceled use a scope created through {@link
387
   * #newDetachedCancellationScope(Runnable)}.
388
   *
389
   * <p>Example of running activities in parallel and cancelling them after a specified timeout.
390
   *
391
   * <pre><code>
392
   *     List&lt;Promise&lt;String&gt;&gt; results = new ArrayList&lt;&gt;();
393
   *     CancellationScope scope = Workflow.newDetachedCancellationScope(() -&gt; {
394
   *        Async.function(activities::a1);
395
   *        Async.function(activities::a2);
396
   *     });
397
   *     scope.run(); // returns immediately as the activities are invoked asynchronously
398
   *     Workflow.sleep(Duration.ofHours(1));
399
   *     // Cancels any activity in the scope that is still running
400
   *     scope.cancel("one hour passed");
401
   *
402
   * </code></pre>
403
   *
404
   * @param runnable parameter to wrap in a cancellation scope.
405
   * @return wrapped parameter.
406
   */
407
  public static CancellationScope newCancellationScope(Runnable runnable) {
408
    return WorkflowInternal.newCancellationScope(false, runnable);
1✔
409
  }
410

411
  /**
412
   * Wraps a procedure in a CancellationScope. The procedure receives the wrapping CancellationScope
413
   * as a parameter. Useful when cancellation is requested from within the wrapped code. The
414
   * following example cancels the sibling activity on any failure.
415
   *
416
   * <pre><code>
417
   *               Workflow.newCancellationScope(
418
   *                   (scope) -&gt; {
419
   *                     Promise<Void> p1 = Async.proc(activities::a1).exceptionally(ex-&gt;
420
   *                        {
421
   *                           scope.cancel("a1 failed");
422
   *                           return null;
423
   *                        });
424
   *
425
   *                     Promise<Void> p2 = Async.proc(activities::a2).exceptionally(ex-&gt;
426
   *                        {
427
   *                           scope.cancel("a2 failed");
428
   *                           return null;
429
   *                        });
430
   *                     Promise.allOf(p1, p2).get();
431
   *                   })
432
   *               .run();
433
   * </code></pre>
434
   *
435
   * @param proc code to wrap in the cancellation scope
436
   * @return wrapped proc
437
   */
438
  public static CancellationScope newCancellationScope(Functions.Proc1<CancellationScope> proc) {
439
    return WorkflowInternal.newCancellationScope(false, proc);
1✔
440
  }
441

442
  /**
443
   * Creates a CancellationScope {@link CancellationScope#run()} that is not linked to a parent
444
   * scope must be called to execute the code the scope wraps. The detached scope is needed to
445
   * execute cleanup code after a workflow is canceled which cancels the root scope that wraps
446
   * the @WorkflowMethod invocation. Here is an example usage:
447
   *
448
   * <pre><code>
449
   *  try {
450
   *     // workflow logic
451
   *  } catch (CanceledFailure e) {
452
   *     CancellationScope detached = Workflow.newDetachedCancellationScope(() -&gt; {
453
   *         // cleanup logic
454
   *     });
455
   *     detached.run();
456
   *  }
457
   * </code></pre>
458
   *
459
   * @param runnable parameter to wrap in a cancellation scope.
460
   * @return wrapped parameter.
461
   * @see #newCancellationScope(Runnable)
462
   */
463
  public static CancellationScope newDetachedCancellationScope(Runnable runnable) {
464
    return WorkflowInternal.newCancellationScope(true, runnable);
1✔
465
  }
466

467
  /**
468
   * Create new timer. Note that Temporal service time resolution is in seconds. So all durations
469
   * are rounded <b>up</b> to the nearest second.
470
   *
471
   * @return feature that becomes ready when at least specified number of seconds passes. promise is
472
   *     failed with {@link CanceledFailure} if enclosing scope is canceled.
473
   */
474
  public static Promise<Void> newTimer(Duration delay) {
475
    return WorkflowInternal.newTimer(delay);
1✔
476
  }
477

478
  /**
479
   * @deprecated use {@link #newWorkflowQueue(int)} instead. An implementation returned by this
480
   *     method has a bug.
481
   */
482
  @Deprecated
483
  public static <E> WorkflowQueue<E> newQueue(int capacity) {
484
    return WorkflowInternal.newQueue(capacity);
×
485
  }
486

487
  /**
488
   * Create a new instance of a {@link WorkflowQueue} implementation that is adapted to be used from
489
   * a workflow code.
490
   *
491
   * @param capacity the maximum size of the queue
492
   * @return new instance of {@link WorkflowQueue}
493
   */
494
  public static <E> WorkflowQueue<E> newWorkflowQueue(int capacity) {
495
    return WorkflowInternal.newWorkflowQueue(capacity);
×
496
  }
497

498
  public static <E> CompletablePromise<E> newPromise() {
499
    return WorkflowInternal.newCompletablePromise();
1✔
500
  }
501

502
  public static <E> Promise<E> newPromise(E value) {
503
    return WorkflowInternal.newPromise(value);
1✔
504
  }
505

506
  public static <E> Promise<E> newFailedPromise(Exception failure) {
507
    return WorkflowInternal.newFailedPromise(failure);
1✔
508
  }
509

510
  /**
511
   * Registers an implementation object. The object must implement at least one interface annotated
512
   * with {@link WorkflowInterface}. All its methods annotated with @{@link SignalMethod}
513
   * and @{@link QueryMethod} are registered.
514
   *
515
   * <p>There is no need to register the top level workflow implementation object as it is done
516
   * implicitly by the framework on object startup.
517
   *
518
   * <p>An attempt to register a duplicated query is going to fail with {@link
519
   * IllegalArgumentException}
520
   */
521
  public static void registerListener(Object listener) {
522
    WorkflowInternal.registerListener(listener);
1✔
523
  }
1✔
524

525
  /**
526
   * Must be used to get current time instead of {@link System#currentTimeMillis()} to guarantee
527
   * determinism.
528
   */
529
  public static long currentTimeMillis() {
530
    return WorkflowInternal.currentTimeMillis();
1✔
531
  }
532

533
  /** Must be called instead of {@link Thread#sleep(long)} to guarantee determinism. */
534
  public static void sleep(Duration duration) {
535
    WorkflowInternal.sleep(duration);
1✔
536
  }
1✔
537

538
  /** Must be called instead of {@link Thread#sleep(long)} to guarantee determinism. */
539
  public static void sleep(long millis) {
540
    WorkflowInternal.sleep(Duration.ofMillis(millis));
1✔
541
  }
1✔
542

543
  /**
544
   * Block current thread until unblockCondition is evaluated to true.
545
   *
546
   * @param unblockCondition condition that should return true to indicate that thread should
547
   *     unblock. The condition is called on every state transition, so it should never call any
548
   *     blocking operations or contain code that mutates any workflow state. It should also not
549
   *     contain any time based conditions. Use {@link #await(Duration, Supplier)} for those
550
   *     instead.
551
   * @throws CanceledFailure if thread (or current {@link CancellationScope} was canceled).
552
   */
553
  public static void await(Supplier<Boolean> unblockCondition) {
554
    WorkflowInternal.await(
1✔
555
        "await",
556
        () -> {
557
          CancellationScope.throwCanceled();
1✔
558
          return unblockCondition.get();
1✔
559
        });
560
  }
1✔
561

562
  /**
563
   * Block current workflow thread until unblockCondition is evaluated to true or timeoutMillis
564
   * passes.
565
   *
566
   * @param timeout time to unblock even if unblockCondition is not satisfied.
567
   * @param unblockCondition condition that should return true to indicate that thread should
568
   *     unblock. The condition is called on every state transition, so it should not contain any
569
   *     code that mutates any workflow state. It should also not contain any time based conditions.
570
   *     Use timeout parameter for those.
571
   * @return false if timed out.
572
   * @throws CanceledFailure if thread (or current {@link CancellationScope} was canceled).
573
   */
574
  public static boolean await(Duration timeout, Supplier<Boolean> unblockCondition) {
575
    return WorkflowInternal.await(
1✔
576
        timeout,
577
        "await",
578
        () -> {
579
          CancellationScope.throwCanceled();
1✔
580
          return unblockCondition.get();
1✔
581
        });
582
  }
583

584
  /**
585
   * Invokes function retrying in case of failures according to retry options. Synchronous variant.
586
   * Use {@link Async#retry(RetryOptions, Optional, Functions.Func)} for asynchronous functions.
587
   *
588
   * @param options retry options that specify retry policy
589
   * @param expiration stop retrying after this interval if provided
590
   * @param fn function to invoke and retry
591
   * @return result of the function or the last failure.
592
   */
593
  public static <R> R retry(
594
      RetryOptions options, Optional<Duration> expiration, Functions.Func<R> fn) {
595
    return WorkflowInternal.retry(options, expiration, fn);
×
596
  }
597

598
  /**
599
   * Invokes function retrying in case of failures according to retry options. Synchronous variant.
600
   * Use {@link Async#retry(RetryOptions, Optional, Functions.Func)} for asynchronous functions.
601
   *
602
   * @param options retry options that specify retry policy
603
   * @param expiration if specified stop retrying after this interval
604
   * @param proc procedure to invoke and retry
605
   */
606
  public static void retry(
607
      RetryOptions options, Optional<Duration> expiration, Functions.Proc proc) {
608
    WorkflowInternal.retry(
×
609
        options,
610
        expiration,
611
        () -> {
612
          proc.apply();
×
613
          return null;
×
614
        });
615
  }
×
616

617
  /**
618
   * If there is a need to return a checked exception from a workflow implementation do not add the
619
   * exception to a method signature but wrap it using this method before rethrowing. The library
620
   * code will unwrap it automatically using when propagating exception to a remote caller. {@link
621
   * RuntimeException} are just returned from this method without modification.
622
   *
623
   * <p>The reason for such design is that returning originally thrown exception from a remote call
624
   * (which child workflow and activity invocations are ) would not allow adding context information
625
   * about a failure, like activity and child workflow id. So stubs always throw a subclass of
626
   * {@link ActivityFailure} from calls to an activity and subclass of {@link ChildWorkflowFailure}
627
   * from calls to a child workflow. The original exception is attached as a cause to these wrapper
628
   * exceptions. So as exceptions are always wrapped adding checked ones to method signature causes
629
   * more pain than benefit.
630
   *
631
   * <p>
632
   *
633
   * <pre>
634
   * try {
635
   *     return someCall();
636
   * } catch (Exception e) {
637
   *     throw Workflow.wrap(e);
638
   * }
639
   * </pre>
640
   *
641
   * @return CheckedExceptionWrapper if e is checked or original exception if e extends
642
   *     RuntimeException.
643
   */
644
  public static RuntimeException wrap(Exception e) {
645
    return WorkflowInternal.wrap(e);
1✔
646
  }
647

648
  /**
649
   * Replay safe way to generate UUID.
650
   *
651
   * <p>Must be used instead of {@link UUID#randomUUID()} which relies on a random generator, thus
652
   * leads to non-deterministic code which is prohibited inside a workflow.
653
   */
654
  public static UUID randomUUID() {
655
    return WorkflowInternal.randomUUID();
1✔
656
  }
657

658
  /** Replay safe random numbers generator. Seeded differently for each workflow instance. */
659
  public static Random newRandom() {
660
    return WorkflowInternal.newRandom();
1✔
661
  }
662

663
  /**
664
   * True if workflow code is being replayed.
665
   *
666
   * <p><b>Warning!</b> Never make workflow logic depend on this flag as it is going to break
667
   * determinism. The only reasonable uses for this flag are deduping external never failing side
668
   * effects like logging or metric reporting.
669
   *
670
   * <p>This method always returns false if called from a non workflow thread.
671
   *
672
   * @deprecated use {@link WorkflowUnsafe#isReplaying()}
673
   */
674
  @Deprecated
675
  public static boolean isReplaying() {
676
    return WorkflowUnsafe.isReplaying();
×
677
  }
678

679
  /**
680
   * Executes the provided function once, records its result into the workflow history. The recorded
681
   * result on history will be returned without executing the provided function during replay. This
682
   * guarantees the deterministic requirement for workflow as the exact same result will be returned
683
   * in replay. Common use case is to run some short non-deterministic code in workflow, like
684
   * getting random number. The only way to fail SideEffect is to panic which causes workflow task
685
   * failure. The workflow task after timeout is rescheduled and re-executed giving SideEffect
686
   * another chance to succeed.
687
   *
688
   * <p>Caution: do not use sideEffect function to modify any workflow state. Only use the
689
   * SideEffect's return value. For example this code is BROKEN:
690
   *
691
   * <pre><code>
692
   *  // Bad example:
693
   *  AtomicInteger random = new AtomicInteger();
694
   *  Workflow.sideEffect(() -&gt; {
695
   *         random.set(random.nextInt(100));
696
   *         return null;
697
   *  });
698
   *  // random will always be 0 in replay, thus this code is non-deterministic
699
   *  if random.get() &lt; 50 {
700
   *         ....
701
   *  } else {
702
   *         ....
703
   *  }
704
   * </code></pre>
705
   *
706
   * On replay the provided function is not executed, the random will always be 0, and the workflow
707
   * could take a different path breaking the determinism.
708
   *
709
   * <p>Here is the correct way to use sideEffect:
710
   *
711
   * <pre><code>
712
   *  // Good example:
713
   *  int random = Workflow.sideEffect(Integer.class, () -&gt; random.nextInt(100));
714
   *  if random &lt; 50 {
715
   *         ....
716
   *  } else {
717
   *         ....
718
   *  }
719
   * </code></pre>
720
   *
721
   * If function throws any exception it is not delivered to the workflow code. It is wrapped in
722
   * {@link Error} causing failure of the current workflow task.
723
   *
724
   * @param resultClass type of the side effect
725
   * @param func function that returns side effect value
726
   * @return value of the side effect
727
   * @see #mutableSideEffect(String, Class, BiPredicate, Functions.Func)
728
   */
729
  public static <R> R sideEffect(Class<R> resultClass, Func<R> func) {
730
    return WorkflowInternal.sideEffect(resultClass, resultClass, func);
1✔
731
  }
732

733
  /**
734
   * Executes the provided function once, records its result into the workflow history. The recorded
735
   * result on history will be returned without executing the provided function during replay. This
736
   * guarantees the deterministic requirement for workflow as the exact same result will be returned
737
   * in replay. Common use case is to run some short non-deterministic code in workflow, like
738
   * getting random number. The only way to fail SideEffect is to panic which causes workflow task
739
   * failure. The workflow task after timeout is rescheduled and re-executed giving SideEffect
740
   * another chance to succeed.
741
   *
742
   * <p>Caution: do not use sideEffect function to modify any workflow state. Only use the
743
   * SideEffect's return value. For example this code is BROKEN:
744
   *
745
   * <pre><code>
746
   *  // Bad example:
747
   *  AtomicInteger random = new AtomicInteger();
748
   *  Workflow.sideEffect(() -&gt; {
749
   *         random.set(random.nextInt(100));
750
   *         return null;
751
   *  });
752
   *  // random will always be 0 in replay, thus this code is non-deterministic
753
   *  if random.get() &lt; 50 {
754
   *         ....
755
   *  } else {
756
   *         ....
757
   *  }
758
   * </code></pre>
759
   *
760
   * On replay the provided function is not executed, the random will always be 0, and the workflow
761
   * could take a different path breaking the determinism.
762
   *
763
   * <p>Here is the correct way to use sideEffect:
764
   *
765
   * <pre><code>
766
   *  // Good example:
767
   *  int random = Workflow.sideEffect(Integer.class, () -&gt; random.nextInt(100));
768
   *  if random &lt; 50 {
769
   *         ....
770
   *  } else {
771
   *         ....
772
   *  }
773
   * </code></pre>
774
   *
775
   * If function throws any exception it is not delivered to the workflow code. It is wrapped in
776
   * {@link Error} causing failure of the current workflow task.
777
   *
778
   * @param resultClass class of the side effect
779
   * @param resultType type of the side effect. Differs from resultClass for generic types.
780
   * @param func function that returns side effect value
781
   * @return value of the side effect
782
   * @see #mutableSideEffect(String, Class, BiPredicate, Functions.Func)
783
   */
784
  public static <R> R sideEffect(Class<R> resultClass, Type resultType, Func<R> func) {
785
    return WorkflowInternal.sideEffect(resultClass, resultType, func);
×
786
  }
787

788
  /**
789
   * {@code mutableSideEffect} is similar to {@link #sideEffect(Class, Functions.Func)} in allowing
790
   * calls of non-deterministic functions from workflow code.
791
   *
792
   * <p>The difference between {@code mutableSideEffect} and {@link #sideEffect(Class,
793
   * Functions.Func)} is that every new {@code sideEffect} call in non-replay mode results in a new
794
   * marker event recorded into the history. However, {@code mutableSideEffect} only records a new
795
   * marker if a value has changed. During the replay, {@code mutableSideEffect} will not execute
796
   * the function again, but it will return the exact same value as it was returning during the
797
   * non-replay run.
798
   *
799
   * <p>One good use case of {@code mutableSideEffect} is to access a dynamically changing config
800
   * without breaking determinism. Even if called very frequently the config value is recorded only
801
   * when it changes not causing any performance degradation due to a large history size.
802
   *
803
   * <p>Caution: do not use {@code mutableSideEffect} function to modify any workflow state. Only
804
   * use the mutableSideEffect's return value.
805
   *
806
   * <p>If function throws any exception it is not delivered to the workflow code. It is wrapped in
807
   * {@link Error} causing failure of the current workflow task.
808
   *
809
   * @param id unique identifier of this side effect
810
   * @param updated used to decide if a new value should be recorded. A func result is recorded only
811
   *     if call to updated with stored and a new value as arguments returns true. It is not called
812
   *     for the first value.
813
   * @param resultClass class of the side effect
814
   * @param func function that produces a value. This function can contain non-deterministic code.
815
   * @see #sideEffect(Class, Functions.Func)
816
   */
817
  public static <R> R mutableSideEffect(
818
      String id, Class<R> resultClass, BiPredicate<R, R> updated, Func<R> func) {
819
    return WorkflowInternal.mutableSideEffect(id, resultClass, resultClass, updated, func);
1✔
820
  }
821

822
  /**
823
   * {@code mutableSideEffect} is similar to {@link #sideEffect(Class, Functions.Func)} in allowing
824
   * calls of non-deterministic functions from workflow code.
825
   *
826
   * <p>The difference between {@code mutableSideEffect} and {@link #sideEffect(Class,
827
   * Functions.Func)} is that every new {@code sideEffect} call in non-replay mode results in a new
828
   * marker event recorded into the history. However, {@code mutableSideEffect} only records a new
829
   * marker if a value has changed. During the replay, {@code mutableSideEffect} will not execute
830
   * the function again, but it will return the exact same value as it was returning during the
831
   * non-replay run.
832
   *
833
   * <p>One good use case of {@code mutableSideEffect} is to access a dynamically changing config
834
   * without breaking determinism. Even if called very frequently the config value is recorded only
835
   * when it changes not causing any performance degradation due to a large history size.
836
   *
837
   * <p>Caution: do not use {@code mutableSideEffect} function to modify any workflow state. Only
838
   * use the mutableSideEffect's return value.
839
   *
840
   * <p>If function throws any exception it is not delivered to the workflow code. It is wrapped in
841
   * {@link Error} causing failure of the current workflow task.
842
   *
843
   * @param id unique identifier of this side effect
844
   * @param updated used to decide if a new value should be recorded. A func result is recorded only
845
   *     if call to updated with stored and a new value as arguments returns true. It is not called
846
   *     for the first value.
847
   * @param resultClass class of the side effect
848
   * @param resultType type of the side effect. Differs from resultClass for generic types.
849
   * @param func function that produces a value. This function can contain non-deterministic code.
850
   * @see #sideEffect(Class, Functions.Func)
851
   */
852
  public static <R> R mutableSideEffect(
853
      String id, Class<R> resultClass, Type resultType, BiPredicate<R, R> updated, Func<R> func) {
854
    return WorkflowInternal.mutableSideEffect(id, resultClass, resultType, updated, func);
×
855
  }
856

857
  /**
858
   * {@code getVersion} is used to safely perform backwards incompatible changes to workflow
859
   * definitions. It is not allowed to update workflow code while there are workflows running as it
860
   * is going to break determinism. The solution is to have both old code that is used to replay
861
   * existing workflows as well as the new one that is used when it is executed for the first time.\
862
   *
863
   * <p>{@code getVersion} returns maxSupported version when is executed for the first time. This
864
   * version is recorded into the workflow history as a marker event. Even if maxSupported version
865
   * is changed the version that was recorded is returned on replay. DefaultVersion constant
866
   * contains version of code that wasn't versioned before.
867
   *
868
   * <p>For example initially workflow has the following code:
869
   *
870
   * <pre><code>
871
   * result = testActivities.activity1();
872
   * </code></pre>
873
   *
874
   * it should be updated to
875
   *
876
   * <pre><code>
877
   * result = testActivities.activity2();
878
   * </code></pre>
879
   *
880
   * The backwards compatible way to execute the update is
881
   *
882
   * <pre><code>
883
   * int version = Workflow.getVersion("fooChange", Workflow.DEFAULT_VERSION, 1);
884
   * String result;
885
   * if (version == Workflow.DEFAULT_VERSION) {
886
   *   result = testActivities.activity1();
887
   * } else {
888
   *   result = testActivities.activity2();
889
   * }
890
   * </code></pre>
891
   *
892
   * Then later if we want to have another change:
893
   *
894
   * <pre><code>
895
   * int version = Workflow.getVersion("fooChange", Workflow.DEFAULT_VERSION, 2);
896
   * String result;
897
   * if (version == Workflow.DEFAULT_VERSION) {
898
   *   result = testActivities.activity1();
899
   * } else if (version == 1) {
900
   *   result = testActivities.activity2();
901
   * } else {
902
   *   result = testActivities.activity3();
903
   * }
904
   * </code></pre>
905
   *
906
   * Later when there are no workflow executions running DefaultVersion the correspondent branch can
907
   * be removed:
908
   *
909
   * <pre><code>
910
   * int version = Workflow.getVersion("fooChange", 1, 2);
911
   * String result;
912
   * if (version == 1) {
913
   *   result = testActivities.activity2();
914
   * } else {
915
   *   result = testActivities.activity3();
916
   * }
917
   * </code></pre>
918
   *
919
   * It is recommended to keep the GetVersion() call even if single branch is left:
920
   *
921
   * <pre><code>
922
   * Workflow.getVersion("fooChange", 2, 2);
923
   * result = testActivities.activity3();
924
   * </code></pre>
925
   *
926
   * The reason to keep it is: 1) it ensures that if there is older version execution still running,
927
   * it will fail here and not proceed; 2) if you ever need to make more changes for “fooChange”,
928
   * for example change activity3 to activity4, you just need to update the maxVersion from 2 to 3.
929
   *
930
   * <p>Note that, you only need to preserve the first call to GetVersion() for each changeId. All
931
   * subsequent call to GetVersion() with same changeId are safe to remove. However, if you really
932
   * want to get rid of the first GetVersion() call as well, you can do so, but you need to make
933
   * sure: 1) all older version executions are completed; 2) you can no longer use “fooChange” as
934
   * changeId. If you ever need to make changes to that same part, you would need to use a different
935
   * changeId like “fooChange-fix2”, and start minVersion from DefaultVersion again.
936
   *
937
   * @param changeId identifier of a particular change. All calls to getVersion that share a
938
   *     changeId are guaranteed to return the same version number. Use this to perform multiple
939
   *     coordinated changes that should be enabled together.
940
   * @param minSupported min version supported for the change
941
   * @param maxSupported max version supported for the change, this version is used as the current
942
   *     one during the original execution.
943
   * @return {@code maxSupported} when is originally executed. Original version recorded in the
944
   *     history on replays.
945
   */
946
  public static int getVersion(String changeId, int minSupported, int maxSupported) {
947
    return WorkflowInternal.getVersion(changeId, minSupported, maxSupported);
1✔
948
  }
949

950
  /**
951
   * Get scope for reporting business metrics in workflow logic. This should be used instead of
952
   * creating new metrics scopes as it is able to dedupe metrics during replay.
953
   *
954
   * <p>The original metrics scope is set through {@link
955
   * WorkflowServiceStubsOptions.Builder#setMetricsScope(Scope)} when a worker starts up.
956
   */
957
  public static Scope getMetricsScope() {
958
    return WorkflowInternal.getMetricsScope();
1✔
959
  }
960

961
  /**
962
   * Get logger to use inside workflow. Logs in replay mode are omitted unless {@link
963
   * WorkerFactoryOptions.Builder#setEnableLoggingInReplay(boolean)} is set to {@code true}.
964
   *
965
   * @param clazz class name to appear in logging.
966
   * @return logger to use in workflow logic.
967
   */
968
  public static Logger getLogger(Class<?> clazz) {
969
    return WorkflowInternal.getLogger(clazz);
1✔
970
  }
971

972
  /**
973
   * Get logger to use inside workflow. Logs in replay mode are omitted unless {@link
974
   * WorkerFactoryOptions.Builder#setEnableLoggingInReplay(boolean)} is set to {@code true}.
975
   *
976
   * @param name name to appear in logging.
977
   * @return logger to use in workflow logic.
978
   */
979
  public static Logger getLogger(String name) {
980
    return WorkflowInternal.getLogger(name);
×
981
  }
982

983
  /**
984
   * GetLastCompletionResult extract last completion result from previous run for this cron
985
   * workflow. This is used in combination with cron schedule. A workflow can be started with an
986
   * optional cron schedule. If a cron workflow wants to pass some data to next schedule, it can
987
   * return any data and that data will become available when next run starts.
988
   *
989
   * @param resultClass class of the return data from last run
990
   * @return result of last run
991
   * @see io.temporal.client.WorkflowOptions.Builder#setCronSchedule(String)
992
   */
993
  public static <R> R getLastCompletionResult(Class<R> resultClass) {
994
    return WorkflowInternal.getLastCompletionResult(resultClass, resultClass);
1✔
995
  }
996

997
  /**
998
   * Extract the latest failure from a previous run of this workflow. If any previous run of this
999
   * workflow has failed, this function returns that failure. If no previous runs have failed, an
1000
   * empty optional is returned. The run you are calling this from may have been created as a retry
1001
   * of the previous failed run or as a next cron invocation for cron workflows.
1002
   *
1003
   * @return The last {@link Exception} that occurred in this workflow, if there has been one.
1004
   */
1005
  public static Optional<Exception> getPreviousRunFailure() {
1006
    return WorkflowInternal.getPreviousRunFailure();
1✔
1007
  }
1008

1009
  /**
1010
   * GetLastCompletionResult extract last completion result from previous run for this cron
1011
   * workflow. This is used in combination with cron schedule. A workflow can be started with an
1012
   * optional cron schedule. If a cron workflow wants to pass some data to next schedule, it can
1013
   * return any data and that data will become available when next run starts.
1014
   *
1015
   * @param resultClass class of the return data from last run
1016
   * @param resultType type of the return data from last run. Differs from resultClass for generic
1017
   *     types.
1018
   * @return result of last run
1019
   */
1020
  public static <R> R getLastCompletionResult(Class<R> resultClass, Type resultType) {
1021
    return WorkflowInternal.getLastCompletionResult(resultClass, resultType);
×
1022
  }
1023

1024
  /**
1025
   * Get a single search attribute.
1026
   *
1027
   * @param name search attribute name
1028
   * @return deserialized search attribute value
1029
   * @throws IllegalStateException if the search attribute value is a collection of multiple (&gt;
1030
   *     1) elements
1031
   * @deprecated use {@link #getTypedSearchAttributes} instead.
1032
   */
1033
  @Deprecated
1034
  @Nullable
1035
  public static <T> T getSearchAttribute(String name) {
1036
    return WorkflowInternal.getSearchAttribute(name);
1✔
1037
  }
1038

1039
  /**
1040
   * Collection returned from this method is immutable. To modify search attributes associated with
1041
   * this workflow use {@link #upsertSearchAttributes(Map)}.
1042
   *
1043
   * <p>Note: This method never returns an empty list. Empty list is considered an absent value for
1044
   * search attributes and will be returned as {@code null}.
1045
   *
1046
   * @param name search attribute name
1047
   * @return immutable list of deserialized search attribute values
1048
   * @deprecated use {@link #getTypedSearchAttributes} instead.
1049
   */
1050
  @Deprecated
1051
  @Nullable
1052
  public static <T> List<T> getSearchAttributeValues(String name) {
1053
    return WorkflowInternal.getSearchAttributeValues(name);
×
1054
  }
1055

1056
  /**
1057
   * Map returned from this method is immutable. To modify search attributes associated with this
1058
   * workflow use {@link #upsertSearchAttributes(Map)}.
1059
   *
1060
   * @return immutable map of search attribute names to deserialized values.
1061
   * @deprecated use {@link #getTypedSearchAttributes} instead.
1062
   */
1063
  @Deprecated
1064
  @Nonnull
1065
  public static Map<String, List<?>> getSearchAttributes() {
1066
    return WorkflowInternal.getSearchAttributes();
1✔
1067
  }
1068

1069
  /**
1070
   * Get immutable set of search attributes. To modify search attributes associated with this
1071
   * workflow use {@link #upsertTypedSearchAttributes}.
1072
   *
1073
   * @return immutable set of search attributes.
1074
   */
1075
  @Nonnull
1076
  public static SearchAttributes getTypedSearchAttributes() {
1077
    return WorkflowInternal.getTypedSearchAttributes();
1✔
1078
  }
1079

1080
  /**
1081
   * Updates Workflow Search Attributes by merging {@code searchAttributes} to the existing Search
1082
   * Attributes map attached to the workflow. Search Attributes are additional indexed information
1083
   * attributed to workflow and used for search and visibility.
1084
   *
1085
   * <p>The search attributes can be used in query of List/Scan/Count workflow APIs. The key and its
1086
   * value type must be registered on Temporal server side.
1087
   *
1088
   * <p>Supported Java types of the value:
1089
   *
1090
   * <ul>
1091
   *   <li>{@link String}
1092
   *   <li>{@link Long}, {@link Integer}, {@link Short}, {@link Byte}
1093
   *   <li>{@link Boolean}
1094
   *   <li>{@link Double}
1095
   *   <li>{@link OffsetDateTime}
1096
   *   <li>{@link Collection} of the types above
1097
   *   <li>{@link io.temporal.common.SearchAttribute#UNSET_VALUE} can be used to unset or remove the
1098
   *       search attribute
1099
   * </ul>
1100
   *
1101
   * For example, workflow code:
1102
   *
1103
   * <pre><code>
1104
   *     Map&lt;String, Object&gt; attr1 = new HashMap&lt;&gt;();
1105
   *     attr1.put("CustomIntField", 1);
1106
   *     attr1.put("CustomBoolField", true);
1107
   *     Workflow.upsertSearchAttributes(attr1);
1108
   *
1109
   *     Map&lt;String, Object&gt; attr2 = new HashMap&lt;&gt;();
1110
   *     attr2.put("CustomIntField", Lists.newArrayList(1, 2));
1111
   *     attr2.put("CustomKeywordField", "Seattle");
1112
   *     Workflow.upsertSearchAttributes(attr2);
1113
   * </pre></code> will eventually have search attributes as:
1114
   *
1115
   * <pre><code>
1116
   *     {
1117
   *       "CustomIntField": 1, 2,
1118
   *       "CustomBoolField": true,
1119
   *       "CustomKeywordField": "Seattle",
1120
   *     }
1121
   * </pre></code>
1122
   *
1123
   * @param searchAttributes map of String to Object value that can be used to search in list APIs
1124
   * @deprecated use {@link #upsertTypedSearchAttributes} instead.
1125
   */
1126
  // WorkflowOptions#setSearchAttributes docs needs to be kept in sync with this method
1127
  @Deprecated
1128
  public static void upsertSearchAttributes(Map<String, ?> searchAttributes) {
1129
    WorkflowInternal.upsertSearchAttributes(searchAttributes);
1✔
1130
  }
1✔
1131

1132
  /**
1133
   * Updates Workflow Search Attributes by applying {@code searchAttributeUpdates} to the existing
1134
   * Search Attributes set attached to the workflow. Search Attributes are additional indexed
1135
   * information attributed to workflow and used for search and visibility.
1136
   *
1137
   * <p>The search attributes can be used in query of List/Scan/Count workflow APIs. The key and its
1138
   * value type must be registered on Temporal server side.
1139
   *
1140
   * @param searchAttributeUpdates set of updates to apply to search attributes.
1141
   */
1142
  public static void upsertTypedSearchAttributes(
1143
      SearchAttributeUpdate<?>... searchAttributeUpdates) {
1144
    WorkflowInternal.upsertTypedSearchAttributes(searchAttributeUpdates);
1✔
1145
  }
1✔
1146

1147
  /**
1148
   * Sets the default activity options that will be used for activity stubs that have no {@link
1149
   * ActivityOptions} specified.<br>
1150
   * This overrides a value provided by {@link
1151
   * WorkflowImplementationOptions#getDefaultActivityOptions}.<br>
1152
   * A more specific per-activity-type option specified in {@link
1153
   * WorkflowImplementationOptions#getActivityOptions} or {@link #applyActivityOptions(Map)} takes
1154
   * precedence over this setting.
1155
   *
1156
   * @param defaultActivityOptions {@link ActivityOptions} to be used as a default
1157
   */
1158
  public static void setDefaultActivityOptions(ActivityOptions defaultActivityOptions) {
1159
    WorkflowInternal.setDefaultActivityOptions(defaultActivityOptions);
1✔
1160
  }
1✔
1161

1162
  /**
1163
   * @deprecated use {@link #applyActivityOptions(Map)}
1164
   */
1165
  @Deprecated
1166
  public static void setActivityOptions(Map<String, ActivityOptions> activityMethodOptions) {
1167
    WorkflowInternal.applyActivityOptions(activityMethodOptions);
×
1168
  }
×
1169

1170
  /**
1171
   * Adds activity options per activity type that will be used for an activity stub that has no
1172
   * {@link ActivityOptions} specified.<br>
1173
   * This method refines an original set of {@code Map<String, ActivityOptions>} provided by {@link
1174
   * WorkflowImplementationOptions#getActivityOptions()}<br>
1175
   * These more specific options take precedence over more generic setting {@link
1176
   * #setDefaultActivityOptions}
1177
   *
1178
   * <p>If an activity type already has a {@link ActivityOptions} set by an earlier call to this
1179
   * method or from {@link WorkflowImplementationOptions#getDefaultActivityOptions}, new {@link
1180
   * ActivityOptions} from {@code activityTypeToOptions} will be merged into the old ones using
1181
   * {@link ActivityOptions.Builder#mergeActivityOptions(ActivityOptions)}
1182
   *
1183
   * @param activityTypeToOptions a map of activity types to {@link ActivityOptions}
1184
   */
1185
  public static void applyActivityOptions(Map<String, ActivityOptions> activityTypeToOptions) {
1186
    WorkflowInternal.applyActivityOptions(activityTypeToOptions);
1✔
1187
  }
1✔
1188

1189
  /**
1190
   * Sets the default local activity options that will be used for activity stubs that have no
1191
   * {@link LocalActivityOptions} specified.<br>
1192
   * This overrides a value provided by {@link
1193
   * WorkflowImplementationOptions#getDefaultLocalActivityOptions}.<br>
1194
   * A more specific per-activity-type option specified in {@link
1195
   * WorkflowImplementationOptions#getLocalActivityOptions} or {@link
1196
   * #applyLocalActivityOptions(Map)} takes precedence over this setting.
1197
   *
1198
   * @param defaultLocalActivityOptions {@link LocalActivityOptions} to be used as a default
1199
   */
1200
  public static void setDefaultLocalActivityOptions(
1201
      LocalActivityOptions defaultLocalActivityOptions) {
1202
    WorkflowInternal.setDefaultLocalActivityOptions(defaultLocalActivityOptions);
1✔
1203
  }
1✔
1204

1205
  /**
1206
   * Adds local activity options per activity type that will be used for a local activity stub that
1207
   * has no {@link LocalActivityOptions} specified.<br>
1208
   * This method refines an original set of {@code Map<String, LocalActivityOptions>} provided by
1209
   * {@link WorkflowImplementationOptions#getLocalActivityOptions()}<br>
1210
   * These more specific options take precedence over more generic setting {@link
1211
   * #setDefaultLocalActivityOptions}
1212
   *
1213
   * <p>If an activity type already has a {@link LocalActivityOptions} set by an earlier call to
1214
   * this method or from {@link WorkflowImplementationOptions#getDefaultLocalActivityOptions}, new
1215
   * {@link LocalActivityOptions} from {@code activityTypeToOptions} will be merged into the old
1216
   * ones using {@link LocalActivityOptions.Builder#mergeActivityOptions(LocalActivityOptions)}
1217
   *
1218
   * @param activityTypeToOptions a map of activity types to {@link LocalActivityOptions}
1219
   */
1220
  public static void applyLocalActivityOptions(
1221
      Map<String, LocalActivityOptions> activityTypeToOptions) {
1222
    WorkflowInternal.applyLocalActivityOptions(activityTypeToOptions);
1✔
1223
  }
1✔
1224

1225
  /** Prohibit instantiation. */
1226
  private Workflow() {}
1227
}
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