UNPKG

durable-execution

Version:

A durable task engine for running tasks durably and resiliently

613 lines 22.3 kB
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