Class Workflow


  • public final class Workflow
    extends java.lang.Object
    This class contains methods exposing Temporal API for Workflows, like
    • Creation and scheduling of activities, child workflows, external workflows, continue-as-new runs
    • Operations over workflow elements, like Side Effects, Timers, Versions, CancellationScope
    • Accessing and updating of the workflow data, like WorkflowInfo, Memos and Search Attributes
    • Deterministic implementation of popular non-deterministic API working with time, logging and generation of random values
    Methods of this class are intended to be called from a workflow method only until explicitly stated otherwise on the specific method's javadoc.

    For an overview of Temporal JavaSDK Workflows, see io.temporal.workflow

    For methods providing Temporal Workflow alternatives to threading and asynchronous invocations, see Async

    See Also:
    io.temporal.workflow
    • Method Detail

      • newActivityStub

        public static <T> T newActivityStub​(java.lang.Class<T> activityInterface)
        Creates client stub to activities that implement given interface. `
        Parameters:
        activityInterface - interface type implemented by activities
      • newActivityStub

        public static <T> T newActivityStub​(java.lang.Class<T> activityInterface,
                                            ActivityOptions options)
        Creates client stub to activities that implement given interface
        Parameters:
        activityInterface - interface type implemented by activities.
        options - options that together with the properties of ActivityMethod specify the activity invocation parameters
      • newActivityStub

        public static <T> T newActivityStub​(java.lang.Class<T> activityInterface,
                                            ActivityOptions options,
                                            java.util.Map<java.lang.String,​ActivityOptions> activityMethodOptions)
        Creates client stub to activities that implement given interface.
        Parameters:
        activityInterface - interface type implemented by activities
        options - options that together with the properties of ActivityMethod specify the activity invocation parameters
        activityMethodOptions - activity method-specific invocation parameters
      • newUntypedActivityStub

        public static ActivityStub newUntypedActivityStub​(ActivityOptions options)
        Creates non typed client stub to activities. Allows executing activities by their string name.
        Parameters:
        options - specify the activity invocation parameters.
      • newLocalActivityStub

        public static <T> T newLocalActivityStub​(java.lang.Class<T> activityInterface)
        Creates client stub to local activities that implement given interface.
        Parameters:
        activityInterface - interface type implemented by activities
      • newLocalActivityStub

        public static <T> T newLocalActivityStub​(java.lang.Class<T> activityInterface,
                                                 LocalActivityOptions options)
        Creates client stub to local activities that implement given interface. A local activity is similar to a regular activity, but with some key differences: 1. Local activity is scheduled and run by the workflow worker locally. 2. Local activity does not need Temporal server to schedule activity task and does not rely on activity worker. 3. Local activity is for short living activities (usually finishes within seconds). 4. Local activity cannot heartbeat.
        Parameters:
        activityInterface - interface type implemented by activities
        options - options that together with the properties of ActivityMethod specify the activity invocation parameters.
      • newLocalActivityStub

        public static <T> T newLocalActivityStub​(java.lang.Class<T> activityInterface,
                                                 LocalActivityOptions options,
                                                 java.util.Map<java.lang.String,​LocalActivityOptions> activityMethodOptions)
        Creates client stub to local activities that implement given interface.
        Parameters:
        activityInterface - interface type implemented by activities
        options - options that together with the properties of ActivityMethod specify the activity invocation parameters
        activityMethodOptions - activity method-specific invocation parameters
      • newUntypedLocalActivityStub

        public static ActivityStub newUntypedLocalActivityStub​(LocalActivityOptions options)
        Creates non typed client stub to local activities. Allows executing activities by their string name.
        Parameters:
        options - specify the local activity invocation parameters.
      • newChildWorkflowStub

        public static <T> T newChildWorkflowStub​(java.lang.Class<T> workflowInterface)
        Creates client stub that can be used to start a child workflow that implements the given interface using parent options. Use newExternalWorkflowStub(Class, String) to get a stub to signal a workflow without starting it.
        Parameters:
        workflowInterface - interface type implemented by activities
      • newChildWorkflowStub

        public static <T> T newChildWorkflowStub​(java.lang.Class<T> workflowInterface,
                                                 ChildWorkflowOptions options)
        Creates client stub that can be used to start a child workflow that implements given interface. Use newExternalWorkflowStub(Class, String) to get a stub to signal a workflow without starting it.
        Parameters:
        workflowInterface - interface type implemented by activities
        options - options passed to the child workflow.
      • newExternalWorkflowStub

        public static <R> R newExternalWorkflowStub​(java.lang.Class<? extends R> workflowInterface,
                                                    java.lang.String workflowId)
        Creates client stub that can be used to communicate to an existing workflow execution.
        Parameters:
        workflowInterface - interface type implemented by activities
        workflowId - id of the workflow to communicate with.
      • newExternalWorkflowStub

        public static <R> R newExternalWorkflowStub​(java.lang.Class<? extends R> workflowInterface,
                                                    io.temporal.api.common.v1.WorkflowExecution execution)
        Creates client stub that can be used to communicate to an existing workflow execution.
        Parameters:
        workflowInterface - interface type implemented by activities
        execution - execution of the workflow to communicate with.
      • newUntypedChildWorkflowStub

        public static ChildWorkflowStub newUntypedChildWorkflowStub​(java.lang.String workflowType,
                                                                    ChildWorkflowOptions options)
        Creates untyped client stub that can be used to start and signal a child workflow.
        Parameters:
        workflowType - name of the workflow type to start.
        options - options passed to the child workflow.
      • newUntypedChildWorkflowStub

        public static ChildWorkflowStub newUntypedChildWorkflowStub​(java.lang.String workflowType)
        Creates untyped client stub that can be used to start and signal a child workflow. All options are inherited from the parent.
        Parameters:
        workflowType - name of the workflow type to start.
      • newUntypedExternalWorkflowStub

        public static ExternalWorkflowStub newUntypedExternalWorkflowStub​(io.temporal.api.common.v1.WorkflowExecution execution)
        Creates untyped client stub that can be used to signal or cancel a child workflow.
        Parameters:
        execution - execution of the workflow to communicate with.
      • newUntypedExternalWorkflowStub

        public static ExternalWorkflowStub newUntypedExternalWorkflowStub​(java.lang.String workflowId)
        Creates untyped client stub that can be used to signal or cancel a child workflow.
        Parameters:
        workflowId - id of the workflow to communicate with.
      • newContinueAsNewStub

        public static <T> T newContinueAsNewStub​(java.lang.Class<T> workflowInterface,
                                                 ContinueAsNewOptions options)
        Creates a client stub that can be used to continue this workflow as a new run.
        Parameters:
        workflowInterface - an interface type implemented by the next run of the workflow
      • newContinueAsNewStub

        public static <T> T newContinueAsNewStub​(java.lang.Class<T> workflowInterface)
        Creates a client stub that can be used to continue this workflow as a new run.
        Parameters:
        workflowInterface - an interface type implemented by the next run of the workflow
      • continueAsNew

        public static void continueAsNew​(java.lang.Object... args)
        Continues the current workflow execution as a new run with the same options.
        Parameters:
        args - arguments of the next run.
        See Also:
        newContinueAsNewStub(Class)
      • continueAsNew

        public static void continueAsNew​(@Nullable
                                         ContinueAsNewOptions options,
                                         java.lang.Object... args)
        Continues the current workflow execution as a new run with the same workflowType and overridden options.
        Parameters:
        options - option overrides for the next run, can contain null if no overrides are needed
        args - arguments of the next run.
        See Also:
        newContinueAsNewStub(Class, ContinueAsNewOptions)
      • continueAsNew

        @Deprecated
        public static void continueAsNew​(java.util.Optional<java.lang.String> workflowType,
                                         java.util.Optional<ContinueAsNewOptions> options,
                                         java.lang.Object... args)
        Continues the current workflow execution as a new run possibly overriding the workflow type and options.
        Parameters:
        workflowType - workflow type override for the next run, can contain null if no override is needed
        options - option overrides for the next run, can contain null if no overrides are needed
        args - arguments of the next run.
        See Also:
        newContinueAsNewStub(Class)
      • continueAsNew

        public static void continueAsNew​(@Nullable
                                         java.lang.String workflowType,
                                         @Nullable
                                         ContinueAsNewOptions options,
                                         java.lang.Object... args)
        Continues the current workflow execution as a new run possibly overriding the workflow type and options.
        Parameters:
        workflowType - workflow type override for the next run, can be null of no override is needed
        options - option overrides for the next run, can be null if no overrides are needed
        args - arguments of the next run.
        See Also:
        newContinueAsNewStub(Class)
      • getMemo

        public static <T> java.lang.Object getMemo​(java.lang.String key,
                                                   java.lang.Class<T> valueClass)
        Extract deserialized Memo associated with given key
        Parameters:
        key - memo key
        valueClass - Java class to deserialize into
        Returns:
        deserialized Memo or null if the key is not present in the memo
      • getMemo

        public static <T> T getMemo​(java.lang.String key,
                                    java.lang.Class<T> valueClass,
                                    java.lang.reflect.Type genericType)
        Extract Memo associated with the given key and deserialized into an object of generic type as is done here: DataConverter.fromPayloads(int, java.util.Optional, java.lang.Class, java.lang.reflect.Type) Ex: To deserialize into HashMap<String, Integer> Workflow.getMemo(key, Map.class, new TypeToken<HashMap<String, Integer>>() {}.getType())
        Parameters:
        key - memo key
        valueClass - Java class to deserialize into
        genericType - type parameter for the generic class
        Returns:
        deserialized Memo or null if the key is not present in the memo
      • newCancellationScope

        public static CancellationScope newCancellationScope​(java.lang.Runnable runnable)
        Wraps the Runnable method argument in a CancellationScope. The Runnable.run() calls Runnable.run() on the wrapped Runnable. The returned CancellationScope can be used to cancel the wrapped code. The cancellation semantic depends on the operation the code is blocked on. For example activity or child workflow is first canceled then throws a CanceledFailure. The same applies for sleep(long) operation. When an activity or a child workflow is invoked asynchronously then they get canceled and a Promise that contains their result will throw CanceledFailure when Promise.get() is called.

        The new cancellation scope CancellationScope.current() is linked to the parent one. If the parent one is canceled then all the children scopes are wrapped within a root cancellation scope which gets canceled when a workflow is canceled through the Temporal CancelWorkflowExecution API. To perform cleanup operations that require blocking after the current scope is canceled use a scope created through newDetachedCancellationScope(Runnable).

        Example of running activities in parallel and cancelling them after a specified timeout.

        
             List<Promise<String>> results = new ArrayList<>();
             CancellationScope scope = Workflow.newDetachedCancellationScope(() -> {
                Async.function(activities::a1);
                Async.function(activities::a2);
             });
             scope.run(); // returns immediately as the activities are invoked asynchronously
             Workflow.sleep(Duration.ofHours(1));
             // Cancels any activity in the scope that is still running
             scope.cancel("one hour passed");
        
         
        Parameters:
        runnable - parameter to wrap in a cancellation scope.
        Returns:
        wrapped parameter.
      • newCancellationScope

        public static CancellationScope newCancellationScope​(Functions.Proc1<CancellationScope> proc)
        Wraps a procedure in a CancellationScope. The procedure receives the wrapping CancellationScope as a parameter. Useful when cancellation is requested from within the wrapped code. The following example cancels the sibling activity on any failure.
        
                       Workflow.newCancellationScope(
                           (scope) -> {
                             Promise p1 = Async.proc(activities::a1).exceptionally(ex->
                                {
                                   scope.cancel("a1 failed");
                                   return null;
                                });
        
                             Promise p2 = Async.proc(activities::a2).exceptionally(ex->
                                {
                                   scope.cancel("a2 failed");
                                   return null;
                                });
                             Promise.allOf(p1, p2).get();
                           })
                       .run();
         
        Parameters:
        proc - code to wrap in the cancellation scope
        Returns:
        wrapped proc
      • newDetachedCancellationScope

        public static CancellationScope newDetachedCancellationScope​(java.lang.Runnable runnable)
        Creates a CancellationScope Runnable.run() that is not linked to a parent scope must be called to execute the code the scope wraps. The detached scope is needed to execute cleanup code after a workflow is canceled which cancels the root scope that wraps the @WorkflowMethod invocation. Here is an example usage:
        
          try {
             // workflow logic
          } catch (CanceledFailure e) {
             CancellationScope detached = Workflow.newDetachedCancellationScope(() -> {
                 // cleanup logic
             });
             detached.run();
          }
         
        Parameters:
        runnable - parameter to wrap in a cancellation scope.
        Returns:
        wrapped parameter.
        See Also:
        newCancellationScope(Runnable)
      • newTimer

        public static Promise<java.lang.Void> newTimer​(java.time.Duration delay)
        Create new timer. Note that Temporal service time resolution is in seconds. So all durations are rounded up to the nearest second.
        Returns:
        feature that becomes ready when at least specified number of seconds passes. promise is failed with CanceledFailure if enclosing scope is canceled.
      • newQueue

        @Deprecated
        public static <E> WorkflowQueue<E> newQueue​(int capacity)
        Deprecated.
      • newWorkflowQueue

        public static <E> WorkflowQueue<E> newWorkflowQueue​(int capacity)
        Create a new instance of a WorkflowQueue implementation that is adapted to be used from a workflow code.
        Parameters:
        capacity - the maximum size of the queue
        Returns:
        new instance of WorkflowQueue
      • newPromise

        public static <E> Promise<E> newPromise​(E value)
      • newFailedPromise

        public static <E> Promise<E> newFailedPromise​(java.lang.Exception failure)
      • registerListener

        public static void registerListener​(java.lang.Object listener)
        Registers an implementation object. The object must implement at least one interface annotated with WorkflowInterface. All its methods annotated with @SignalMethod and @QueryMethod are registered.

        There is no need to register the top level workflow implementation object as it is done implicitly by the framework on object startup.

        An attempt to register a duplicated query is going to fail with IllegalArgumentException

      • currentTimeMillis

        public static long currentTimeMillis()
        Must be used to get current time instead of System.currentTimeMillis() to guarantee determinism.
      • sleep

        public static void sleep​(java.time.Duration duration)
        Must be called instead of Thread.sleep(long) to guarantee determinism.
      • sleep

        public static void sleep​(long millis)
        Must be called instead of Thread.sleep(long) to guarantee determinism.
      • await

        public static void await​(java.util.function.Supplier<java.lang.Boolean> unblockCondition)
        Block current thread until unblockCondition is evaluated to true.
        Parameters:
        unblockCondition - condition that should return true to indicate that thread should unblock. The condition is called on every state transition, so it should never call any blocking operations or contain code that mutates any workflow state. It should also not contain any time based conditions. Use await(Duration, Supplier) for those instead.
        Throws:
        CanceledFailure - if thread (or current CancellationScope was canceled).
      • await

        public static boolean await​(java.time.Duration timeout,
                                    java.util.function.Supplier<java.lang.Boolean> unblockCondition)
        Block current workflow thread until unblockCondition is evaluated to true or timeoutMillis passes.
        Parameters:
        timeout - time to unblock even if unblockCondition is not satisfied.
        unblockCondition - condition that should return true to indicate that thread should unblock. The condition is called on every state transition, so it should not contain any code that mutates any workflow state. It should also not contain any time based conditions. Use timeout parameter for those.
        Returns:
        false if timed out.
        Throws:
        CanceledFailure - if thread (or current CancellationScope was canceled).
      • retry

        public static <R> R retry​(RetryOptions options,
                                  java.util.Optional<java.time.Duration> expiration,
                                  Functions.Func<R> fn)
        Invokes function retrying in case of failures according to retry options. Synchronous variant. Use Async.retry(RetryOptions, Optional, Functions.Func) for asynchronous functions.
        Parameters:
        options - retry options that specify retry policy
        expiration - stop retrying after this interval if provided
        fn - function to invoke and retry
        Returns:
        result of the function or the last failure.
      • retry

        public static void retry​(RetryOptions options,
                                 java.util.Optional<java.time.Duration> expiration,
                                 Functions.Proc proc)
        Invokes function retrying in case of failures according to retry options. Synchronous variant. Use Async.retry(RetryOptions, Optional, Functions.Func) for asynchronous functions.
        Parameters:
        options - retry options that specify retry policy
        expiration - if specified stop retrying after this interval
        proc - procedure to invoke and retry
      • wrap

        public static java.lang.RuntimeException wrap​(java.lang.Exception e)
        If there is a need to return a checked exception from a workflow implementation do not add the exception to a method signature but wrap it using this method before rethrowing. The library code will unwrap it automatically using when propagating exception to a remote caller. RuntimeException are just returned from this method without modification.

        The reason for such design is that returning originally thrown exception from a remote call (which child workflow and activity invocations are ) would not allow adding context information about a failure, like activity and child workflow id. So stubs always throw a subclass of ActivityFailure from calls to an activity and subclass of ChildWorkflowFailure from calls to a child workflow. The original exception is attached as a cause to these wrapper exceptions. So as exceptions are always wrapped adding checked ones to method signature causes more pain than benefit.

         try {
             return someCall();
         } catch (Exception e) {
             throw Workflow.wrap(e);
         }
         
        Returns:
        CheckedExceptionWrapper if e is checked or original exception if e extends RuntimeException.
      • randomUUID

        public static java.util.UUID randomUUID()
        Replay safe way to generate UUID.

        Must be used instead of UUID.randomUUID() which relies on a random generator, thus leads to non-deterministic code which is prohibited inside a workflow.

      • newRandom

        public static java.util.Random newRandom()
        Replay safe random numbers generator. Seeded differently for each workflow instance.
      • isReplaying

        @Deprecated
        public static boolean isReplaying()
        Deprecated.
        True if workflow code is being replayed.

        Warning! Never make workflow logic depend on this flag as it is going to break determinism. The only reasonable uses for this flag are deduping external never failing side effects like logging or metric reporting.

        This method always returns false if called from a non workflow thread.

      • sideEffect

        public static <R> R sideEffect​(java.lang.Class<R> resultClass,
                                       Functions.Func<R> func)
        Executes the provided function once, records its result into the workflow history. The recorded result on history will be returned without executing the provided function during replay. This guarantees the deterministic requirement for workflow as the exact same result will be returned in replay. Common use case is to run some short non-deterministic code in workflow, like getting random number. The only way to fail SideEffect is to panic which causes workflow task failure. The workflow task after timeout is rescheduled and re-executed giving SideEffect another chance to succeed.

        Caution: do not use sideEffect function to modify any workflow state. Only use the SideEffect's return value. For example this code is BROKEN:

        
          // Bad example:
          AtomicInteger random = new AtomicInteger();
          Workflow.sideEffect(() -> {
                 random.set(random.nextInt(100));
                 return null;
          });
          // random will always be 0 in replay, thus this code is non-deterministic
          if random.get() < 50 {
                 ....
          } else {
                 ....
          }
         
        On replay the provided function is not executed, the random will always be 0, and the workflow could take a different path breaking the determinism.

        Here is the correct way to use sideEffect:

        
          // Good example:
          int random = Workflow.sideEffect(Integer.class, () -> random.nextInt(100));
          if random < 50 {
                 ....
          } else {
                 ....
          }
         
        If function throws any exception it is not delivered to the workflow code. It is wrapped in Error causing failure of the current workflow task.
        Parameters:
        resultClass - type of the side effect
        func - function that returns side effect value
        Returns:
        value of the side effect
        See Also:
        mutableSideEffect(String, Class, BiPredicate, Functions.Func)
      • sideEffect

        public static <R> R sideEffect​(java.lang.Class<R> resultClass,
                                       java.lang.reflect.Type resultType,
                                       Functions.Func<R> func)
        Executes the provided function once, records its result into the workflow history. The recorded result on history will be returned without executing the provided function during replay. This guarantees the deterministic requirement for workflow as the exact same result will be returned in replay. Common use case is to run some short non-deterministic code in workflow, like getting random number. The only way to fail SideEffect is to panic which causes workflow task failure. The workflow task after timeout is rescheduled and re-executed giving SideEffect another chance to succeed.

        Caution: do not use sideEffect function to modify any workflow state. Only use the SideEffect's return value. For example this code is BROKEN:

        
          // Bad example:
          AtomicInteger random = new AtomicInteger();
          Workflow.sideEffect(() -> {
                 random.set(random.nextInt(100));
                 return null;
          });
          // random will always be 0 in replay, thus this code is non-deterministic
          if random.get() < 50 {
                 ....
          } else {
                 ....
          }
         
        On replay the provided function is not executed, the random will always be 0, and the workflow could take a different path breaking the determinism.

        Here is the correct way to use sideEffect:

        
          // Good example:
          int random = Workflow.sideEffect(Integer.class, () -> random.nextInt(100));
          if random < 50 {
                 ....
          } else {
                 ....
          }
         
        If function throws any exception it is not delivered to the workflow code. It is wrapped in Error causing failure of the current workflow task.
        Parameters:
        resultClass - class of the side effect
        resultType - type of the side effect. Differs from resultClass for generic types.
        func - function that returns side effect value
        Returns:
        value of the side effect
        See Also:
        mutableSideEffect(String, Class, BiPredicate, Functions.Func)
      • mutableSideEffect

        public static <R> R mutableSideEffect​(java.lang.String id,
                                              java.lang.Class<R> resultClass,
                                              java.util.function.BiPredicate<R,​R> updated,
                                              Functions.Func<R> func)
        mutableSideEffect is similar to sideEffect(Class, Functions.Func) in allowing calls of non-deterministic functions from workflow code.

        The difference between mutableSideEffect and sideEffect(Class, Functions.Func) is that every new sideEffect call in non-replay mode results in a new marker event recorded into the history. However, mutableSideEffect only records a new marker if a value has changed. During the replay, mutableSideEffect will not execute the function again, but it will return the exact same value as it was returning during the non-replay run.

        One good use case of mutableSideEffect is to access a dynamically changing config without breaking determinism. Even if called very frequently the config value is recorded only when it changes not causing any performance degradation due to a large history size.

        Caution: do not use mutableSideEffect function to modify any workflow state. Only use the mutableSideEffect's return value.

        If function throws any exception it is not delivered to the workflow code. It is wrapped in Error causing failure of the current workflow task.

        Parameters:
        id - unique identifier of this side effect
        updated - used to decide if a new value should be recorded. A func result is recorded only if call to updated with stored and a new value as arguments returns true. It is not called for the first value.
        resultClass - class of the side effect
        func - function that produces a value. This function can contain non-deterministic code.
        See Also:
        sideEffect(Class, Functions.Func)
      • mutableSideEffect

        public static <R> R mutableSideEffect​(java.lang.String id,
                                              java.lang.Class<R> resultClass,
                                              java.lang.reflect.Type resultType,
                                              java.util.function.BiPredicate<R,​R> updated,
                                              Functions.Func<R> func)
        mutableSideEffect is similar to sideEffect(Class, Functions.Func) in allowing calls of non-deterministic functions from workflow code.

        The difference between mutableSideEffect and sideEffect(Class, Functions.Func) is that every new sideEffect call in non-replay mode results in a new marker event recorded into the history. However, mutableSideEffect only records a new marker if a value has changed. During the replay, mutableSideEffect will not execute the function again, but it will return the exact same value as it was returning during the non-replay run.

        One good use case of mutableSideEffect is to access a dynamically changing config without breaking determinism. Even if called very frequently the config value is recorded only when it changes not causing any performance degradation due to a large history size.

        Caution: do not use mutableSideEffect function to modify any workflow state. Only use the mutableSideEffect's return value.

        If function throws any exception it is not delivered to the workflow code. It is wrapped in Error causing failure of the current workflow task.

        Parameters:
        id - unique identifier of this side effect
        updated - used to decide if a new value should be recorded. A func result is recorded only if call to updated with stored and a new value as arguments returns true. It is not called for the first value.
        resultClass - class of the side effect
        resultType - type of the side effect. Differs from resultClass for generic types.
        func - function that produces a value. This function can contain non-deterministic code.
        See Also:
        sideEffect(Class, Functions.Func)
      • getVersion

        public static int getVersion​(java.lang.String changeId,
                                     int minSupported,
                                     int maxSupported)
        getVersion is used to safely perform backwards incompatible changes to workflow definitions. It is not allowed to update workflow code while there are workflows running as it is going to break determinism. The solution is to have both old code that is used to replay existing workflows as well as the new one that is used when it is executed for the first time.\

        getVersion returns maxSupported version when is executed for the first time. This version is recorded into the workflow history as a marker event. Even if maxSupported version is changed the version that was recorded is returned on replay. DefaultVersion constant contains version of code that wasn't versioned before.

        For example initially workflow has the following code:

        
         result = testActivities.activity1();
         
        it should be updated to
        
         result = testActivities.activity2();
         
        The backwards compatible way to execute the update is
        
         int version = Workflow.getVersion("fooChange", Workflow.DEFAULT_VERSION, 1);
         String result;
         if (version == Workflow.DEFAULT_VERSION) {
           result = testActivities.activity1();
         } else {
           result = testActivities.activity2();
         }
         
        Then later if we want to have another change:
        
         int version = Workflow.getVersion("fooChange", Workflow.DEFAULT_VERSION, 2);
         String result;
         if (version == Workflow.DEFAULT_VERSION) {
           result = testActivities.activity1();
         } else if (version == 1) {
           result = testActivities.activity2();
         } else {
           result = testActivities.activity3();
         }
         
        Later when there are no workflow executions running DefaultVersion the correspondent branch can be removed:
        
         int version = Workflow.getVersion("fooChange", 1, 2);
         String result;
         if (version == 1) {
           result = testActivities.activity2();
         } else {
           result = testActivities.activity3();
         }
         
        It is recommended to keep the GetVersion() call even if single branch is left:
        
         Workflow.getVersion("fooChange", 2, 2);
         result = testActivities.activity3();
         
        The reason to keep it is: 1) it ensures that if there is older version execution still running, it will fail here and not proceed; 2) if you ever need to make more changes for “fooChange”, for example change activity3 to activity4, you just need to update the maxVersion from 2 to 3.

        Note that, you only need to preserve the first call to GetVersion() for each changeId. All subsequent call to GetVersion() with same changeId are safe to remove. However, if you really want to get rid of the first GetVersion() call as well, you can do so, but you need to make sure: 1) all older version executions are completed; 2) you can no longer use “fooChange” as changeId. If you ever need to make changes to that same part, you would need to use a different changeId like “fooChange-fix2”, and start minVersion from DefaultVersion again.

        Parameters:
        changeId - identifier of a particular change. All calls to getVersion that share a changeId are guaranteed to return the same version number. Use this to perform multiple coordinated changes that should be enabled together.
        minSupported - min version supported for the change
        maxSupported - max version supported for the change
        Returns:
        version
      • getMetricsScope

        public static com.uber.m3.tally.Scope getMetricsScope()
        Get scope for reporting business metrics in workflow logic. This should be used instead of creating new metrics scopes as it is able to dedupe metrics during replay.

        The original metrics scope is set through WorkflowServiceStubsOptions.Builder.setMetricsScope(Scope) when a worker starts up.

      • getLogger

        public static org.slf4j.Logger getLogger​(java.lang.Class<?> clazz)
        Get logger to use inside workflow. Logs in replay mode are omitted unless WorkerFactoryOptions.Builder.setEnableLoggingInReplay(boolean) is set to true.
        Parameters:
        clazz - class name to appear in logging.
        Returns:
        logger to use in workflow logic.
      • getLogger

        public static org.slf4j.Logger getLogger​(java.lang.String name)
        Get logger to use inside workflow. Logs in replay mode are omitted unless WorkerFactoryOptions.Builder.setEnableLoggingInReplay(boolean) is set to true.
        Parameters:
        name - name to appear in logging.
        Returns:
        logger to use in workflow logic.
      • getLastCompletionResult

        public static <R> R getLastCompletionResult​(java.lang.Class<R> resultClass)
        GetLastCompletionResult extract last completion result from previous run for this cron workflow. This is used in combination with cron schedule. A workflow can be started with an optional cron schedule. If a cron workflow wants to pass some data to next schedule, it can return any data and that data will become available when next run starts.
        Parameters:
        resultClass - class of the return data from last run
        Returns:
        result of last run
        See Also:
        WorkflowOptions.Builder.setCronSchedule(String)
      • getPreviousRunFailure

        public static java.util.Optional<java.lang.Exception> getPreviousRunFailure()
        Extract the latest failure from some previous of this workflow. If any previous run of this workflow has failed, this function returns that failure. If no previous runs have failed, an empty optional is returned. The run you are calling this from may have been created as a retry of the previous failed run or as a next cron invocation for cron workflows.
        Returns:
        The last Exception that occurred in this workflow, if there has been one.
      • getLastCompletionResult

        public static <R> R getLastCompletionResult​(java.lang.Class<R> resultClass,
                                                    java.lang.reflect.Type resultType)
        GetLastCompletionResult extract last completion result from previous run for this cron workflow. This is used in combination with cron schedule. A workflow can be started with an optional cron schedule. If a cron workflow wants to pass some data to next schedule, it can return any data and that data will become available when next run starts.
        Parameters:
        resultClass - class of the return data from last run
        resultType - type of the return data from last run. Differs from resultClass for generic types.
        Returns:
        result of last run
      • upsertSearchAttributes

        public static void upsertSearchAttributes​(java.util.Map<java.lang.String,​java.lang.Object> searchAttributes)
        upsertSearchAttributes is used to add or update workflow search attributes. The search attributes can be used in query of List/Scan/Count workflow APIs. The key and value type must be registered on Temporal server side; The value has to be Json serializable. UpsertSearchAttributes will merge attributes to existing map in workflow, for example workflow code:
        
             Map<String, Object> attr1 = new HashMap<>();
             attr1.put("CustomIntField", 1);
             attr1.put("CustomBoolField", true);
             Workflow.upsertSearchAttributes(attr1);
        
             Map<String, Object> attr2 = new HashMap<>();
             attr2.put("CustomIntField", 2);
             attr2.put("CustomKeywordField", "Seattle");
             Workflow.upsertSearchAttributes(attr2);
         
        will eventually have search attributes as:
        
             {
               "CustomIntField": 2,
               "CustomBoolField": true,
               "CustomKeywordField": "Seattle",
             }
         
        Parameters:
        searchAttributes - map of String to Object value that can be used to search in list APIs