durable-execution
Version:
A durable task engine for running tasks durably and resiliently
613 lines • 22.3 kB
TypeScript
import type { CancelSignal } from './cancel';
import type { DurableExecutionError, DurableExecutionErrorStorageObject } from './errors';
/**
* A durable task that can be run using a durable executor. See the
* [usage](https://gpahal.github.io/durable-execution/index.html#usage) and
* [task examples](https://gpahal.github.io/durable-execution/index.html#task-examples) sections
* for more details on creating and enqueuing tasks.
*
* @category Task
*/
export type DurableTask<TInput, TOutput> = {
id: string;
};
/**
* Common options for a durable task. These options are used by both {@link DurableTaskOptions} and
* {@link DurableParentTaskOptions}.
*
* @category Task
*/
export type DurableTaskCommonOptions = {
/**
* A unique identifier for the task. Can only contain alphanumeric characters and underscores.
* The identifier must be unique among all the durable tasks in the same durable executor.
*/
id: string;
/**
* The options for retrying the task.
*/
retryOptions?: DurableTaskRetryOptions;
/**
* The delay before running the task run function. If the value is < 0 or undefined, it will be
* treated as 0.
*/
sleepMsBeforeRun?: number;
/**
* The timeout for the task run function. If a value < 0 is returned, the task will be marked as
* failed and will not be retried.
*/
timeoutMs: number;
};
/**
* The options for retrying a durable task. The delay after nth retry is calculated as:
* `baseDelayMs * (delayMultiplier ** n)`. The delay is capped at `maxDelayMs` if provided.
*
* @category Task
*/
export type DurableTaskRetryOptions = {
/**
* The maximum number of times the task can be retried.
*/
maxAttempts: number;
/**
* The base delay before each retry. Defaults to 1000 or 1 second.
*/
baseDelayMs?: number;
/**
* The multiplier for the delay before each retry. Default is 1.
*/
delayMultiplier?: number;
/**
* The maximum delay before each retry.
*/
maxDelayMs?: number;
};
/**
* Options for a durable task that can be run using a durable executor. A task is resilient to task
* failures, process failures, network connectivity issues, and other transient errors. The task
* should be idempotent as it may be run multiple times if there is a process failure or if the
* task is retried.
*
* When enqueued with an executor, a {@link DurableTaskHandle} is returned. It supports getting
* the execution status, waiting for the task to complete, and cancelling the task.
*
* The output of the {@link run} function is the output of the task.
*
* The input and output are serialized and deserialized using the serializer passed to the durable
* executor.
*
* Make sure the id is unique among all the durable tasks in the same durable executor. If two
* tasks are registered with the same id, the second one will overwrite the first one, even if the
* first one is enqueued.
*
* The tasks can be added to an executor using the {@link DurableExecutor.task} method. If the input
* to a task needs to be validated, it can be done using the {@link DurableExecutor.validateInput}
* or {@link DurableExecutor.inputSchema} methods.
*
* See the [task examples](https://gpahal.github.io/durable-execution/index.html#task-examples)
* section for more details on creating tasks.
*
* @example
* ```ts
* const extractFileTitle = executor
* .inputSchema(v.object({ filePath: v.string() }))
* .task({
* id: 'extractFileTitle',
* timeoutMs: 30_000, // 30 seconds
* run: async (ctx, input) => {
* // ... extract the file title
* return {
* title: 'File Title',
* }
* },
* })
* ```
*
* @category Task
*/
export type DurableTaskOptions<TInput = unknown, TOutput = unknown> = DurableTaskCommonOptions & {
/**
* The task run logic. It returns the output.
*
* Behavior on throwing errors:
* - If the task throws an error or a `{@link DurableExecutionError}`, the task will be marked as
* failed
* - If the task throws a `{@link DurableExecutionTimedOutError}`, it will be marked as timed out
* - If the task throws a `{@link DurableExecutionCancelledError}`, it will be marked as cancelled
* - Failed and timed out tasks might be retried based on the task's retry configuration
* - Cancelled tasks will not be retried
*
* @param ctx - The context object to the task.
* @param input - The input to the task.
* @returns The output of the task.
*/
run: (ctx: DurableTaskRunContext, input: TInput) => TOutput | Promise<TOutput>;
};
/**
* Options for a durable parent task that can be run using a durable executor. It is similar to
* {@link DurableTaskOptions} but it returns children tasks to be run in parallel after the run
* function completes, along with the output of the parent task.
*
* The {@link runParent} function is similar to the `run` function in {@link DurableTaskOptions},
* but the output is of the form `{ output: TRunOutput, childrenTasks: Array<DurableChildTask> }` where
* the children are the tasks to be run in parallel after the run function completes.
*
* The {@link finalizeTask} task is run after the runParent function and all the children tasks
* complete. It is useful for combining the output of the runParent function and children tasks.
* It's input has the following properties:
*
* - `input`: The input of the `finalizeTask` task. Same as the input of runParent function
* - `output`: The output of the runParent function
* - `childrenTasksOutputs`: The outputs of the children tasks
*
* If {@link finalizeTask} is provided, the output of the whole task is the output of the
* {@link finalizeTask} task. If it is not provided, the output of the whole task is the output of
* the form `{ output: TRunOutput, childrenTasksOutputs: Array<DurableChildTaskExecutionOutput> }`.
*
* See the [task examples](https://gpahal.github.io/durable-execution/index.html#task-examples)
* section for more details on creating tasks.
*
* @example
* ```ts
* const extractFileTitle = executor
* .inputSchema(v.object({ filePath: v.string() }))
* .task({
* id: 'extractFileTitle',
* timeoutMs: 30_000, // 30 seconds
* run: async (ctx, input) => {
* // ... extract the file title
* return {
* title: 'File Title',
* }
* },
* })
*
* const summarizeFile = executor
* .validateInput(async (input: { filePath: string }) => {
* if (!isValidFilePath(input.filePath)) {
* throw new Error('Invalid file path')
* }
* return {
* filePath: input.filePath,
* }
* })
* .task({
* id: 'summarizeFile',
* timeoutMs: 30_000, // 30 seconds
* run: async (ctx, input) => {
* // ... summarize the file
* return {
* summary: 'File summary',
* }
* },
* })
*
* const uploadFile = executor
* .inputSchema(v.object({ filePath: v.string(), uploadUrl: v.string() }))
* .parentTask({
* id: 'uploadFile',
* timeoutMs: 60_000, // 1 minute
* runParent: async (ctx, input) => {
* // ... upload file to the given uploadUrl
* // Extract the file title and summarize the file in parallel
* return {
* output: {
* filePath: input.filePath,
* uploadUrl: input.uploadUrl,
* fileSize: 100,
* },
* childrenTasks: [
* {
* task: extractFileTitle,
* input: { filePath: input.filePath },
* },
* {
* task: summarizeFile,
* input: { filePath: input.filePath },
* },
* ],
* }
* },
* finalizeTask: {
* id: 'onUploadFileAndChildrenComplete',
* timeoutMs: 60_000, // 1 minute
* run: async (ctx, { input, output, childrenTasksOutputs }) => {
* // ... combine the output of the run function and children tasks
* return {
* filePath: input.filePath,
* uploadUrl: input.uploadUrl,
* fileSize: 100,
* title: 'File Title',
* summary: 'File summary',
* }
* }
* },
* })
* ```
*
* @category Task
*/
export type DurableParentTaskOptions<TInput = unknown, TRunOutput = unknown, TOutput = {
output: TRunOutput;
childrenTasksOutputs: Array<DurableChildTaskExecutionOutput>;
}, TFinalizeTaskRunOutput = unknown> = DurableTaskCommonOptions & {
/**
* The task run logic. It is similar to the `run` function in {@link DurableTaskOptions} but it
* returns the output and children tasks to be run in parallel after the run function completes.
*
* @param ctx - The context object to the task.
* @param input - The input of the task.
* @returns The output of the task and children tasks to be run in parallel after the run
* function completes.
*/
runParent: (ctx: DurableTaskRunContext, input: TInput) => {
output: TRunOutput;
childrenTasks?: Array<DurableChildTask>;
} | Promise<{
output: TRunOutput;
childrenTasks?: Array<DurableChildTask>;
}>;
/**
* Task to run after the runParent function and children tasks complete. This is useful for
* combining the output of the run function and children tasks.
*/
finalizeTask?: DurableFinalizeTaskOptions<TInput, TRunOutput, TOutput, TFinalizeTaskRunOutput>;
};
/**
* Options for the `finalizeTask` property in {@link DurableParentTaskOptions}. It is similar to
* {@link DurableTaskOptions} or {@link DurableParentTaskOptions} but the input is of the form:
*
* ```ts
* {
* input: TRunInput,
* output: TRunOutput,
* childrenTasksOutputs: Array<DurableChildTaskExecutionOutput>
* }
* ```
*
* No validation is done on the input and the output of the parent task is the output of the
* `finalizeTask` task.
*
* @category Task
*/
export type DurableFinalizeTaskOptions<TInput = unknown, TRunOutput = unknown, TOutput = unknown, TFinalizeTaskRunOutput = unknown> = DurableTaskOptions<DurableTaskOnChildrenCompleteInput<TInput, TRunOutput>, TOutput> | DurableParentTaskOptions<DurableTaskOnChildrenCompleteInput<TInput, TRunOutput>, TFinalizeTaskRunOutput, TOutput>;
export declare function isDurableFinalizeTaskOptionsTaskOptions<TInput = unknown, TRunOutput = unknown, TOutput = unknown, TFinalizeTaskRunOutput = unknown>(options: DurableFinalizeTaskOptions<TInput, TRunOutput, TOutput, TFinalizeTaskRunOutput>): options is DurableTaskOptions<DurableTaskOnChildrenCompleteInput<TInput, TRunOutput>, TOutput>;
export declare function isDurableFinalizeTaskOptionsParentTaskOptions<TInput = unknown, TRunOutput = unknown, TOutput = unknown, TFinalizeTaskRunOutput = unknown>(options: DurableFinalizeTaskOptions<TInput, TRunOutput, TOutput, TFinalizeTaskRunOutput>): options is DurableParentTaskOptions<DurableTaskOnChildrenCompleteInput<TInput, TRunOutput>, TFinalizeTaskRunOutput, TOutput>;
/**
* The input type for the on children complete task.
*
* @category Task
*/
export type DurableTaskOnChildrenCompleteInput<TInput = unknown, TRunOutput = unknown> = {
input: TInput;
output: TRunOutput;
childrenTasksOutputs: Array<DurableChildTaskExecutionOutput>;
};
/**
* The context object passed to a durable task when it is run.
*
* @category Task
*/
export type DurableTaskRunContext = {
/**
* The task id.
*/
taskId: string;
/**
* The task execution id.
*/
executionId: string;
/**
* The cancel signal of the task. It can be used to gracefully shutdown the task run function
* when the task has been cancelled.
*/
cancelSignal: CancelSignal;
/**
* The shutdown signal of the executor. It is cancelled when the executor is shutting down.
* It can be used to gracefully shutdown the task when executor is shutting down.
*/
shutdownSignal: CancelSignal;
/**
* The attempt number of the task. The first attempt is 0, the second attempt is 1, etc.
*/
attempt: number;
/**
* The error of the previous attempt.
*/
prevError?: DurableExecutionErrorStorageObject;
};
/**
* An execution of a durable task. See
* [Durable task execution](https://gpahal.github.io/durable-execution/index.html#durable-task-execution)
* docs for more details on how task executions work.
*
* @category Task
*/
export type DurableTaskExecution<TOutput = unknown> = DurableTaskReadyExecution | DurableTaskRunningExecution | DurableTaskFailedExecution | DurableTaskTimedOutExecution | DurableTaskWaitingForChildrenTasksExecution | DurableTaskChildrenTasksFailedExecution | DurableTaskWaitingForFinalizeTaskExecution | DurableTaskFinalizeTaskFailedExecution | DurableTaskCompletedExecution<TOutput> | DurableTaskCancelledExecution;
/**
* A finished execution of a durable task. See
* [Durable task execution](https://gpahal.github.io/durable-execution/index.html#durable-task-execution)
* docs for more details on how task executions work.
*
* @category Task
*/
export type DurableTaskFinishedExecution<TOutput = unknown> = DurableTaskFailedExecution | DurableTaskTimedOutExecution | DurableTaskChildrenTasksFailedExecution | DurableTaskFinalizeTaskFailedExecution | DurableTaskCompletedExecution<TOutput> | DurableTaskCancelledExecution;
/**
* A durable task execution that is ready to be run.
*
* @category Task
*/
export type DurableTaskReadyExecution = {
rootTask?: {
taskId: string;
executionId: string;
};
parentTask?: {
taskId: string;
executionId: string;
};
taskId: string;
executionId: string;
retryOptions: DurableTaskRetryOptions;
sleepMsBeforeRun: number;
timeoutMs: number;
runInput: unknown;
error?: DurableExecutionErrorStorageObject;
status: 'ready';
retryAttempts: number;
createdAt: Date;
updatedAt: Date;
};
/**
* A durable task execution that is running.
*
* @category Task
*/
export type DurableTaskRunningExecution = Omit<DurableTaskReadyExecution, 'status'> & {
status: 'running';
startedAt: Date;
expiresAt: Date;
};
/**
* A durable task execution that failed while running.
*
* @category Task
*/
export type DurableTaskFailedExecution = Omit<DurableTaskRunningExecution, 'status' | 'error'> & {
status: 'failed';
error: DurableExecutionErrorStorageObject;
finishedAt: Date;
};
/**
* A durable task execution that timed out while running.
*
* @category Task
*/
export type DurableTaskTimedOutExecution = Omit<DurableTaskRunningExecution, 'status' | 'error'> & {
status: 'timed_out';
error: DurableExecutionErrorStorageObject;
finishedAt: Date;
};
/**
* A durable task execution that is waiting for children tasks to complete.
*
* @category Task
*/
export type DurableTaskWaitingForChildrenTasksExecution = Omit<DurableTaskRunningExecution, 'status' | 'error'> & {
status: 'waiting_for_children_tasks';
runOutput: unknown;
childrenTasks: Array<DurableChildTaskExecution>;
};
/**
* A durable task execution that failed while waiting for children tasks to complete because of one
* or more child task executions failed.
*
* @category Task
*/
export type DurableTaskChildrenTasksFailedExecution = Omit<DurableTaskWaitingForChildrenTasksExecution, 'status'> & {
status: 'children_tasks_failed';
childrenTasksErrors: Array<DurableChildTaskExecutionErrorStorageObject>;
finishedAt: Date;
};
/**
* A durable task execution that is waiting for the finalize task to complete.
*
* @category Task
*/
export type DurableTaskWaitingForFinalizeTaskExecution = Omit<DurableTaskWaitingForChildrenTasksExecution, 'status' | 'error'> & {
status: 'waiting_for_finalize_task';
finalizeTask: DurableChildTaskExecution;
};
/**
* A durable task execution that failed while waiting for the finalize task to complete because the
* finalize task execution failed.
*
* @category Task
*/
export type DurableTaskFinalizeTaskFailedExecution = Omit<DurableTaskWaitingForFinalizeTaskExecution, 'status'> & {
status: 'finalize_task_failed';
finalizeTaskError: DurableExecutionErrorStorageObject;
finishedAt: Date;
};
/**
* A durable task execution that completed successfully.
*
* @category Task
*/
export type DurableTaskCompletedExecution<TOutput = unknown> = Omit<DurableTaskWaitingForChildrenTasksExecution, 'status' | 'output'> & {
status: 'completed';
output: TOutput;
/**
* The finalize task execution. This is only present for tasks which have a finalize task.
*/
finalizeTask?: DurableChildTaskExecution;
finishedAt: Date;
};
/**
* A durable task execution that was cancelled. This can happen when a task is cancelled by using
* the cancel method of the task handle or when the task is cancelled because it's parent task
* failed.
*
* @category Task
*/
export type DurableTaskCancelledExecution = Omit<DurableTaskRunningExecution, 'status' | 'error'> & {
status: 'cancelled';
error: DurableExecutionErrorStorageObject;
/**
* The output of the task. This is only present for tasks whose run method completed
* successfully.
*/
runOutput?: unknown;
/**
* The children tasks that were running when the task was cancelled. This is only present for
* tasks whose run method completed successfully.
*/
childrenTasks?: Array<DurableChildTaskExecution>;
/**
* The finalize task execution. This is only present for tasks which have a finalize task and
* whose run method completed successfully.
*/
finalizeTask?: DurableChildTaskExecution;
finishedAt: Date;
};
/**
* A child task of a durable task.
*
* @category Task
*/
export type DurableChildTask<TInput = unknown, TOutput = unknown> = {
task: DurableTask<TInput, TOutput>;
input: TInput;
options?: DurableTaskEnqueueOptions;
};
/**
* An execution of a child task of a durable task.
*
* @category Task
*/
export type DurableChildTaskExecution = {
taskId: string;
executionId: string;
};
/**
* A child task output of a durable task.
*
* @category Task
*/
export type DurableChildTaskExecutionOutput<TOutput = unknown> = {
index: number;
taskId: string;
executionId: string;
output: TOutput;
};
/**
* A child task error of a durable task.
*
* @category Task
*/
export type DurableChildTaskExecutionError = {
index: number;
taskId: string;
executionId: string;
error: DurableExecutionError;
};
/**
* A storage object for a child task execution error of a durable task execution.
*
* @category Task
*/
export type DurableChildTaskExecutionErrorStorageObject = {
index: number;
taskId: string;
executionId: string;
error: DurableExecutionErrorStorageObject;
};
/**
* A storage object for the status of a durable task execution.
*
* @category Storage
*/
export type DurableTaskExecutionStatusStorageObject = 'ready' | 'running' | 'failed' | 'timed_out' | 'waiting_for_children_tasks' | 'children_tasks_failed' | 'waiting_for_finalize_task' | 'finalize_task_failed' | 'completed' | 'cancelled';
export declare const ALL_TASK_EXECUTION_STATUSES_STORAGE_OBJECTS: Array<DurableTaskExecutionStatusStorageObject>;
export declare const ACTIVE_TASK_EXECUTION_STATUSES_STORAGE_OBJECTS: Array<DurableTaskExecutionStatusStorageObject>;
export declare const FINISHED_TASK_EXECUTION_STATUSES_STORAGE_OBJECTS: Array<DurableTaskExecutionStatusStorageObject>;
/**
* The options for enqueuing a task. If provided, the task will be enqueued with the given
* options. If not provided, the task will be enqueued with the default options provided in the
* task options.
*
* @category Task
*/
export type DurableTaskEnqueueOptions = {
retryOptions?: DurableTaskRetryOptions;
sleepMsBeforeRun?: number;
timeoutMs?: number;
};
/**
* A handle to a durable task execution. See
* [Durable task execution](https://gpahal.github.io/durable-execution/index.html#durable-task-execution)
* docs for more details on how task executions work.
*
* @example
* ```ts
* const handle = await executor.enqueueTask(uploadFile, {filePath: 'file.txt'})
* // Get the task execution
* const execution = await handle.getExecution()
*
* // Wait for the task execution to be finished and get it
* const finishedExecution = await handle.waitAndGetExecution()
* if (finishedExecution.status === 'completed') {
* // Do something with the result
* } else if (finishedExecution.status === 'failed') {
* // Do something with the error
* } else if (finishedExecution.status === 'timed_out') {
* // Do something with the timeout
* } else if (finishedExecution.status === 'cancelled') {
* // Do something with the cancellation
* } else if (finishedExecution.status === 'children_tasks_failed') {
* // Do something with the children tasks failure
* } else if (finishedExecution.status === 'finalize_task_failed') {
* // Do something with the finalize task failure
* }
*
* // Cancel the task execution
* await handle.cancel()
* ```
*
* @category Task
*/
export type DurableTaskHandle<TOutput = unknown> = {
/**
* Get the task id of the durable task.
*
* @returns The task id of the durable task.
*/
getTaskId: () => string;
/**
* Get the execution id of the durable task execution.
*
* @returns The execution id of the durable task execution.
*/
getTaskExecutionId: () => string;
/**
* Get the durable task execution.
*
* @returns The durable task execution.
*/
getTaskExecution: () => Promise<DurableTaskExecution<TOutput>>;
/**
* Wait for the durable task execution to be finished and get it.
*
* @param options - The options for waiting for the durable task execution.
* @returns The durable task execution.
*/
waitAndGetTaskFinishedExecution: (options?: {
signal?: CancelSignal | AbortSignal;
pollingIntervalMs?: number;
}) => Promise<DurableTaskFinishedExecution<TOutput>>;
/**
* Cancel the durable task execution.
*/
cancel: () => Promise<void>;
};
//# sourceMappingURL=task.d.ts.map