All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.durabletask.TaskOrchestrationContext Maven / Gradle / Ivy

Go to download

This package contains classes and interfaces for building Durable Task orchestrations in Java.

There is a newer version: 1.5.0
Show newest version
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.durabletask;

import javax.annotation.Nullable;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.List;

/**
 * Used by orchestrators to perform actions such as scheduling tasks, durable timers, waiting for external events,
 * and for getting basic information about the current orchestration.
 */
public interface TaskOrchestrationContext {
    /**
     * Gets the name of the current task orchestration.
     * @return the name of the current task orchestration
     */
    String getName();

    /**
     * Gets the deserialized input of the current task orchestration.
     *
     * @param targetType the {@link Class} object associated with {@code V}
     * @param  the expected type of the orchestrator input
     * @return the deserialized input as an object of type {@code V} or {@code null} if no input was provided.
     */
     V getInput(Class targetType);

    /**
     * Gets the unique ID of the current orchestration instance.
     * @return the unique ID of the current orchestration instance
     */
    String getInstanceId();

    /**
     * Gets the current orchestration time in UTC.
     * @return the current orchestration time in UTC
     */
    Instant getCurrentInstant();

    /**
     * Gets a value indicating whether the orchestrator is currently replaying a previous execution.
     * 

* Orchestrator functions are "replayed" after being unloaded from memory to reconstruct local variable state. * During a replay, previously executed tasks will be completed automatically with previously seen values * that are stored in the orchestration history. One the orchestrator reaches the point in the orchestrator * where it's no longer replaying existing history, this method will return {@code false}. *

* You can use this method if you have logic that needs to run only when not replaying. For example, * certain types of application logging may become too noisy when duplicated as part of replay. The * application code could check to see whether the function is being replayed and then issue the log statements * when this value is {@code false}. * * @return {@code true} if the orchestrator is replaying, otherwise {@code false} */ boolean getIsReplaying(); // TODO: Update the description of allOf to be more specific about the exception behavior. // https://github.com/microsoft/durabletask-java/issues/54 /** * Returns a new {@code Task} that is completed when all the given {@code Task}s complete. If any of the given * {@code Task}s complete with an exception, the returned {@code Task} will also complete with an exception * containing details of the first encountered failure. The value of the returned {@code Task} is an ordered list of * the return values of the given tasks. If no tasks are provided, returns a {@code Task} completed with value * {@code null}. *

* This method is useful for awaiting the completion of a set of independent tasks before continuing to the next * step in the orchestration, as in the following example: *

{@code
     * Task t1 = ctx.callActivity("MyActivity", String.class);
     * Task t2 = ctx.callActivity("MyActivity", String.class);
     * Task t3 = ctx.callActivity("MyActivity", String.class);
     *
     * List orderedResults = ctx.allOf(List.of(t1, t2, t3)).await();
     * }
* * @param tasks the list of {@code Task} objects * @param the return type of the {@code Task} objects * @return the values of the completed {@code Task} objects in the same order as the source list */ Task> allOf(List> tasks); /** * Returns a new {@code Task} that is completed when any of the tasks in {@code tasks} completes. * See {@link #anyOf(Task[])} for more detailed information. * * @param tasks the list of {@code Task} objects * @return a new {@code Task} that is completed when any of the given {@code Task}s complete * @see #anyOf(Task[]) */ Task> anyOf(List> tasks); /** * Returns a new {@code Task} that is completed when any of the given {@code Task}s complete. The value of the * new {@code Task} is a reference to the completed {@code Task} object. If no tasks are provided, returns a * {@code Task} that never completes. *

* This method is useful for waiting on multiple concurrent tasks and performing a task-specific operation when the * first task completes, as in the following example: *

{@code
     * Task event1 = ctx.waitForExternalEvent("Event1");
     * Task event2 = ctx.waitForExternalEvent("Event2");
     * Task event3 = ctx.waitForExternalEvent("Event3");
     *
     * Task winner = ctx.anyOf(event1, event2, event3).await();
     * if (winner == event1) {
     *     // ...
     * } else if (winner == event2) {
     *     // ...
     * } else if (winner == event3) {
     *     // ...
     * }
     * }
* The {@code anyOf} method can also be used for implementing long-running timeouts, as in the following example: *
{@code
     * Task activityTask = ctx.callActivity("SlowActivity");
     * Task timeoutTask = ctx.createTimer(Duration.ofMinutes(30));
     *
     * Task winner = ctx.anyOf(activityTask, timeoutTask).await();
     * if (winner == activityTask) {
     *     // completion case
     * } else {
     *     // timeout case
     * }
     * }
* * @param tasks the list of {@code Task} objects * @return a new {@code Task} that is completed when any of the given {@code Task}s complete */ default Task> anyOf(Task... tasks) { return this.anyOf(Arrays.asList(tasks)); } /** * Creates a durable timer that expires after the specified delay. *

* Specifying a long delay (for example, a delay of a few days or more) may result in the creation of multiple, * internally-managed durable timers. The orchestration code doesn't need to be aware of this behavior. However, * it may be visible in framework logs and the stored history state. * * @param delay the amount of time before the timer should expire * @return a new {@code Task} that completes after the specified delay */ Task createTimer(Duration delay); /** * Transitions the orchestration into the {@link OrchestrationRuntimeStatus#COMPLETED} state with the given output. * * @param output the serializable output of the completed orchestration */ void complete(Object output); /** * Asynchronously invokes an activity by name and with the specified input value and returns a new {@link Task} * that completes when the activity completes. If the activity completes successfully, the returned {@code Task}'s * value will be the activity's output. If the activity fails, the returned {@code Task} will complete exceptionally * with a {@link TaskFailedException}. *

* Activities are the basic unit of work in a durable task orchestration. Unlike orchestrators, which are not * allowed to do any I/O or call non-deterministic APIs, activities have no implementation restrictions. *

* An activity may execute in the local machine or a remote machine. The exact behavior depends on the underlying * storage provider, which is responsible for distributing tasks across machines. In general, you should never make * any assumptions about where an activity will run. You should also assume at-least-once execution guarantees for * activities, meaning that an activity may be executed twice if, for example, there is a process failure before * the activities result is saved into storage. *

* Both the inputs and outputs of activities are serialized and stored in durable storage. It's highly recommended * to not include any sensitive data in activity inputs or outputs. It's also recommended to not use large payloads * for activity inputs and outputs, which can result in expensive serialization and network utilization. For data * that cannot be cheaply or safely persisted to storage, it's recommended to instead pass references * (for example, a URL to a storage blog) to the data and have activities fetch the data directly as part of their * implementation. * * @param name the name of the activity to call * @param input the serializable input to pass to the activity * @param options additional options that control the execution and processing of the activity * @param returnType the expected class type of the activity output * @param the expected type of the activity output * @return a new {@link Task} that completes when the activity completes or fails */ Task callActivity(String name, Object input, TaskOptions options, Class returnType); /** * Asynchronously invokes an activity by name and returns a new {@link Task} that completes when the activity * completes. See {@link #callActivity(String, Object, TaskOptions, Class)} for a complete description. * * @see #callActivity(String, Object, TaskOptions, Class) * @param name the name of the activity to call * @return a new {@link Task} that completes when the activity completes or fails */ default Task callActivity(String name) { return this.callActivity(name, Void.class); } /** * Asynchronously invokes an activity by name and with the specified input value and returns a new {@link Task} * that completes when the activity completes. See {@link #callActivity(String, Object, TaskOptions, Class)} for a * complete description. * * @param name the name of the activity to call * @param input the serializable input to pass to the activity * @return a new {@link Task} that completes when the activity completes or fails */ default Task callActivity(String name, Object input) { return this.callActivity(name, input, null, Void.class); } /** * Asynchronously invokes an activity by name and returns a new {@link Task} that completes when the activity * completes. If the activity completes successfully, the returned {@code Task}'s value will be the activity's * output. See {@link #callActivity(String, Object, TaskOptions, Class)} for a complete description. * * @param name the name of the activity to call * @param returnType the expected class type of the activity output * @param the expected type of the activity output * @return a new {@link Task} that completes when the activity completes or fails */ default Task callActivity(String name, Class returnType) { return this.callActivity(name, null, null, returnType); } /** * Asynchronously invokes an activity by name and with the specified input value and returns a new {@link Task} * that completes when the activity completes.If the activity completes successfully, the returned {@code Task}'s * value will be the activity's output. See {@link #callActivity(String, Object, TaskOptions, Class)} for a * complete description. * * @param name the name of the activity to call * @param input the serializable input to pass to the activity * @param returnType the expected class type of the activity output * @param the expected type of the activity output * @return a new {@link Task} that completes when the activity completes or fails */ default Task callActivity(String name, Object input, Class returnType) { return this.callActivity(name, input, null, returnType); } /** * Asynchronously invokes an activity by name and with the specified input value and returns a new {@link Task} * that completes when the activity completes. See {@link #callActivity(String, Object, TaskOptions, Class)} for a * complete description. * * @param name the name of the activity to call * @param input the serializable input to pass to the activity * @param options additional options that control the execution and processing of the activity * @return a new {@link Task} that completes when the activity completes or fails */ default Task callActivity(String name, Object input, TaskOptions options) { return this.callActivity(name, input, options, Void.class); } /** * Restarts the orchestration with a new input and clears its history. See {@link #continueAsNew(Object, boolean)} * for a full description. * * @param input the serializable input data to re-initialize the instance with */ default void continueAsNew(Object input){ this.continueAsNew(input, true); } /** * Restarts the orchestration with a new input and clears its history. *

* This method is primarily designed for eternal orchestrations, which are orchestrations that * may not ever complete. It works by restarting the orchestration, providing it with a new input, * and truncating the existing orchestration history. It allows an orchestration to continue * running indefinitely without having its history grow unbounded. The benefits of periodically * truncating history include decreased memory usage, decreased storage volumes, and shorter orchestrator * replays when rebuilding state. *

* The results of any incomplete tasks will be discarded when an orchestrator calls {@code continueAsNew}. * For example, if a timer is scheduled and then {@code continueAsNew} is called before the timer fires, the timer * event will be discarded. The only exception to this is external events. By default, if an external event is * received by an orchestration but not yet processed, the event is saved in the orchestration state unit it is * received by a call to {@link #waitForExternalEvent}. These events will remain in memory * even after an orchestrator restarts using {@code continueAsNew}. This behavior can be disabled by specifying * {@code false} for the {@code preserveUnprocessedEvents} parameter value. *

* Orchestrator implementations should complete immediately after calling the{@code continueAsNew} method. * * @param input the serializable input data to re-initialize the instance with * @param preserveUnprocessedEvents {@code true} to push unprocessed external events into the new orchestration * history, otherwise {@code false} */ void continueAsNew(Object input, boolean preserveUnprocessedEvents); /** * Sends an external event to another orchestration instance. * * @param instanceID the unique ID of the receiving orchestration instance. * @param eventName the name of the event to send */ default void sendEvent(String instanceID, String eventName){ this.sendEvent(instanceID, eventName, null); } /** * Sends an external event to another orchestration instance. * * @param instanceId the unique ID of the receiving orchestration instance. * @param eventName the name of the event to send * @param eventData the payload of the event to send */ void sendEvent(String instanceId, String eventName, Object eventData); /** * Asynchronously invokes another orchestrator as a sub-orchestration and returns a {@link Task} that completes * when the sub-orchestration completes. *

* See {@link #callSubOrchestrator(String, Object, String, TaskOptions, Class)} for a full description. * * @see #callSubOrchestrator(String, Object, String, TaskOptions, Class) * @param name the name of the orchestrator to invoke * @return a new {@link Task} that completes when the sub-orchestration completes or fails */ default Task callSubOrchestrator(String name){ return this.callSubOrchestrator(name, null); } /** * Asynchronously invokes another orchestrator as a sub-orchestration and returns a {@link Task} that completes * when the sub-orchestration completes. *

* See {@link #callSubOrchestrator(String, Object, String, TaskOptions, Class)} for a full description. * * @param name the name of the orchestrator to invoke * @param input the serializable input to send to the sub-orchestration * @return a new {@link Task} that completes when the sub-orchestration completes or fails */ default Task callSubOrchestrator(String name, Object input) { return this.callSubOrchestrator(name, input, null); } /** * Asynchronously invokes another orchestrator as a sub-orchestration and returns a {@link Task} that completes * when the sub-orchestration completes. *

* See {@link #callSubOrchestrator(String, Object, String, TaskOptions, Class)} for a full description. * * @param name the name of the orchestrator to invoke * @param input the serializable input to send to the sub-orchestration * @param returnType the expected class type of the sub-orchestration output * @param the expected type of the sub-orchestration output * @return a new {@link Task} that completes when the sub-orchestration completes or fails */ default Task callSubOrchestrator(String name, Object input, Class returnType) { return this.callSubOrchestrator(name, input, null, returnType); } /** * Asynchronously invokes another orchestrator as a sub-orchestration and returns a {@link Task} that completes * when the sub-orchestration completes. *

* See {@link #callSubOrchestrator(String, Object, String, TaskOptions, Class)} for a full description. * * @param name the name of the orchestrator to invoke * @param input the serializable input to send to the sub-orchestration * @param instanceID the unique ID of the sub-orchestration * @param returnType the expected class type of the sub-orchestration output * @param the expected type of the sub-orchestration output * @return a new {@link Task} that completes when the sub-orchestration completes or fails */ default Task callSubOrchestrator(String name, Object input, String instanceID, Class returnType) { return this.callSubOrchestrator(name, input, instanceID, null, returnType); } /** * Asynchronously invokes another orchestrator as a sub-orchestration and returns a {@link Task} that completes * when the sub-orchestration completes. *

* See {@link #callSubOrchestrator(String, Object, String, TaskOptions, Class)} for a full description. * * @param name the name of the orchestrator to invoke * @param input the serializable input to send to the sub-orchestration * @param instanceID the unique ID of the sub-orchestration * @param options additional options that control the execution and processing of the activity * @return a new {@link Task} that completes when the sub-orchestration completes or fails */ default Task callSubOrchestrator(String name, Object input, String instanceID, TaskOptions options) { return this.callSubOrchestrator(name, input, instanceID, options, Void.class); } /** * Asynchronously invokes another orchestrator as a sub-orchestration and returns a {@link Task} that completes * when the sub-orchestration completes. If the sub-orchestration completes successfully, the returned * {@code Task}'s value will be the activity's output. If the sub-orchestration fails, the returned {@code Task} * will complete exceptionally with a {@link TaskFailedException}. *

* A sub-orchestration has its own instance ID, history, and status that is independent of the parent orchestrator * that started it. There are many advantages to breaking down large orchestrations into sub-orchestrations: *

    *
  • * Splitting large orchestrations into a series of smaller sub-orchestrations can make code more maintainable. *
  • *
  • * Distributing orchestration logic across multiple compute nodes concurrently is useful if * orchestration logic otherwise needs to coordinate a lot of tasks. *
  • *
  • * Memory usage and CPU overhead can be reduced by keeping the history of parent orchestrations smaller. *
  • *
* The disadvantage is that there is overhead associated with starting a sub-orchestration and processing its * output. This is typically only an issue for very small orchestrations. *

* Because sub-orchestrations are independent of their parents, terminating a parent orchestration does not affect * any sub-orchestrations. Sub-orchestrations must be terminated independently using their unique instance ID, * which is specified using the {@code instanceID} parameter * * @param name the name of the orchestrator to invoke * @param input the serializable input to send to the sub-orchestration * @param instanceID the unique ID of the sub-orchestration * @param options additional options that control the execution and processing of the activity * @param returnType the expected class type of the sub-orchestration output * @param the expected type of the sub-orchestration output * @return a new {@link Task} that completes when the sub-orchestration completes or fails */ Task callSubOrchestrator( String name, @Nullable Object input, @Nullable String instanceID, @Nullable TaskOptions options, Class returnType); /** * Waits for an event to be raised named {@code name} and returns a {@link Task} that completes when the event is * received or is canceled when {@code timeout} expires. *

* External clients can raise events to a waiting orchestration instance using the * {@link DurableTaskClient#raiseEvent} method. *

* If the current orchestration is not yet waiting for an event named {@code name}, then the event will be saved in * the orchestration instance state and dispatched immediately when this method is called. This event saving occurs * even if the current orchestrator cancels the wait operation before the event is received. *

* Orchestrators can wait for the same event name multiple times, so waiting for multiple events with the same name * is allowed. Each external event received by an orchestrator will complete just one task returned by this method. * * @param name the case-insensitive name of the event to wait for * @param timeout the amount of time to wait before canceling the returned {@code Task} * @param dataType the expected class type of the event data payload * @param the expected type of the event data payload * @return a new {@link Task} that completes when the external event is received or when {@code timeout} expires * @throws TaskCanceledException if the specified {@code timeout} value expires before the event is received */ Task waitForExternalEvent(String name, Duration timeout, Class dataType) throws TaskCanceledException; /** * Waits for an event to be raised named {@code name} and returns a {@link Task} that completes when the event is * received or is canceled when {@code timeout} expires. *

* See {@link #waitForExternalEvent(String, Duration, Class)} for a full description. * * @param name the case-insensitive name of the event to wait for * @param timeout the amount of time to wait before canceling the returned {@code Task} * @return a new {@link Task} that completes when the external event is received or when {@code timeout} expires * @throws TaskCanceledException if the specified {@code timeout} value expires before the event is received */ default Task waitForExternalEvent(String name, Duration timeout) throws TaskCanceledException { return this.waitForExternalEvent(name, timeout, Void.class); } /** * Waits for an event to be raised named {@code name} and returns a {@link Task} that completes when the event is * received. *

* See {@link #waitForExternalEvent(String, Duration, Class)} for a full description. * * @param name the case-insensitive name of the event to wait for * @return a new {@link Task} that completes when the external event is received */ default Task waitForExternalEvent(String name) { return this.waitForExternalEvent(name, Void.class); } /** * Waits for an event to be raised named {@code name} and returns a {@link Task} that completes when the event is * received. *

* See {@link #waitForExternalEvent(String, Duration, Class)} for a full description. * * @param name the case-insensitive name of the event to wait for * @param dataType the expected class type of the event data payload * @param the expected type of the event data payload * @return a new {@link Task} that completes when the external event is received */ default Task waitForExternalEvent(String name, Class dataType) { try { return this.waitForExternalEvent(name, null, dataType); } catch (TaskCanceledException e) { // This should never happen because of the max duration throw new RuntimeException("An unexpected exception was throw while waiting for an external event.", e); } } /** * Assigns a custom status value to the current orchestration. *

* The {@code customStatus} value is serialized and stored in orchestration state and will be made available to the * orchestration status query APIs, such as {@link DurableTaskClient#getInstanceMetadata}. The serialized value * must not exceed 16 KB of UTF-16 encoded text. *

* Use {@link #clearCustomStatus()} to remove the custom status value from the orchestration state. * * @param customStatus A serializable value to assign as the custom status value. */ void setCustomStatus(Object customStatus); /** * Clears the orchestration's custom status. */ void clearCustomStatus(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy