Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
fcf15cc
feat: Enhance retry mechanism with failure handling and context
YunchuWang Feb 5, 2026
b05cd0f
feat: Implement advanced retry features with handleFailure predicate …
YunchuWang Feb 6, 2026
157f357
feat: Implement AsyncRetryHandler and refactor retry task handling
YunchuWang Feb 6, 2026
93d2af8
feat: Refactor taskType to use RetryTaskType in RetryHandlerTask and …
YunchuWang Feb 6, 2026
eceb158
feat: Add E2E tests for AsyncRetryHandler with activity and sub-orche…
YunchuWang Feb 6, 2026
957c0b8
Merge branch 'main' into wangbill/retryhandler
YunchuWang Feb 6, 2026
c34b2ea
Update packages/durabletask-js/src/task/retry/retry-policy.ts
YunchuWang Feb 6, 2026
8ebd6af
Update packages/durabletask-js/src/task/retry/retry-handler.ts
YunchuWang Feb 6, 2026
6f5cb2f
feat: Add taskName getter to RetryTaskBase and log retry attempts in …
YunchuWang Feb 6, 2026
554ba1e
Merge branch 'wangbill/retryhandler' of https://github.com/microsoft/…
YunchuWang Feb 6, 2026
3e10cdb
Update packages/durabletask-js/src/task/retry/retry-policy.ts
YunchuWang Feb 6, 2026
522996e
feat: Enhance retry handler functionality with orchestration context …
YunchuWang Feb 6, 2026
4c4a906
Merge branch 'wangbill/retryhandler' of https://github.com/microsoft/…
YunchuWang Feb 6, 2026
4293820
fix unit tests
YunchuWang Feb 6, 2026
4dda8a8
fix: Preserve custom error names in failure details and adjust retry …
YunchuWang Feb 6, 2026
c8e8fd2
refactor: Defer exception creation in recordFailure method and adjust…
YunchuWang Feb 6, 2026
7a02ceb
refactor: Remove isCancelled property from RetryContext and related t…
YunchuWang Feb 6, 2026
154f118
refactor: Remove unused retry handler options and related tests
YunchuWang Feb 7, 2026
39a30cc
fix: Ensure non-null handler in RetryHandlerTask constructor
YunchuWang Feb 7, 2026
f2d0287
feat: Enhance retry handling with support for delay in milliseconds a…
YunchuWang Feb 7, 2026
47c011a
feat: Add updateAction method to RetryTaskBase and synchronize action…
YunchuWang Feb 7, 2026
a133620
feat: Enhance retry handler to support returning delays and add compr…
YunchuWang Feb 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 19 additions & 1 deletion packages/durabletask-js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,36 @@ export {
// Proto types (for advanced usage)
export { OrchestrationStatus as ProtoOrchestrationStatus } from "./proto/orchestrator_service_pb";

// Failure details
export { FailureDetails, TaskFailureDetails } from "./task/failure-details";

// Task utilities
export { getName, whenAll, whenAny } from "./task";
export { Task } from "./task/task";

// Retry policies and task options
export { RetryPolicy, RetryPolicyOptions } from "./task/retry";
export {
RetryPolicy,
RetryPolicyOptions,
FailureHandlerPredicate,
RetryContext,
createRetryContext,
RetryHandler,
AsyncRetryHandler,
toAsyncRetryHandler,
} from "./task/retry";
export {
TaskOptions,
SubOrchestrationOptions,
StartOrchestrationOptions,
TaskRetryOptions,
taskOptionsFromRetryPolicy,
taskOptionsFromRetryHandler,
taskOptionsFromSyncRetryHandler,
subOrchestrationOptionsFromRetryPolicy,
subOrchestrationOptionsFromRetryHandler,
isRetryPolicy,
isRetryHandler,
} from "./task/options";

// Types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export class TaskFailedError extends Error {

constructor(message: string, details: pb.TaskFailureDetails) {
super(message);
this.name = "TaskFailedError";

this._details = new FailureDetails(
details.getErrormessage(),
Expand Down
15 changes: 14 additions & 1 deletion packages/durabletask-js/src/task/failure-details.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

export class FailureDetails {
/**
* Interface representing task failure details.
* This is used for retry handlers to inspect failure information.
*/
export interface TaskFailureDetails {
/** The type/class name of the error */
readonly errorType: string;
/** The error message */
readonly message: string;
/** The stack trace, if available */
readonly stackTrace?: string;
}

export class FailureDetails implements TaskFailureDetails {
private _message: string;
private _errorType: string;
private _stackTrace: string | undefined;
Expand Down
6 changes: 6 additions & 0 deletions packages/durabletask-js/src/task/options/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ export {
TaskOptions,
SubOrchestrationOptions,
StartOrchestrationOptions,
TaskRetryOptions,
taskOptionsFromRetryPolicy,
taskOptionsFromRetryHandler,
taskOptionsFromSyncRetryHandler,
subOrchestrationOptionsFromRetryPolicy,
subOrchestrationOptionsFromRetryHandler,
isRetryPolicy,
isRetryHandler,
} from "./task-options";
107 changes: 104 additions & 3 deletions packages/durabletask-js/src/task/options/task-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,31 @@
// Licensed under the MIT License.

import { RetryPolicy } from "../retry/retry-policy";
import { AsyncRetryHandler, RetryHandler, toAsyncRetryHandler } from "../retry/retry-handler";

/**
* Union type representing the available retry strategies for a task.
*
* - {@link RetryPolicy} for declarative retry control (with backoff, max attempts, etc.)
* - {@link AsyncRetryHandler} for asynchronous imperative retry control
* - {@link RetryHandler} for synchronous imperative retry control
*
* When a synchronous {@link RetryHandler} is provided, it is automatically
* wrapped into an {@link AsyncRetryHandler} internally.
*/
export type TaskRetryOptions = RetryPolicy | AsyncRetryHandler | RetryHandler;

/**
* Options that can be used to control the behavior of orchestrator task execution.
*/
export interface TaskOptions {
/**
* The retry policy for the task.
* Controls how many times a task is retried and the delay between retries.
* The retry options for the task.
* Can be a RetryPolicy for declarative retry control,
* an AsyncRetryHandler for async imperative retry control,
* or a RetryHandler for sync imperative retry control.
*/
retry?: RetryPolicy;
retry?: TaskRetryOptions;
/**
* The tags to associate with the task.
*/
Expand Down Expand Up @@ -81,6 +96,48 @@ export function taskOptionsFromRetryPolicy(policy: RetryPolicy): TaskOptions {
return { retry: policy };
}

/**
* Creates a TaskOptions instance from an AsyncRetryHandler.
*
* @param handler - The async retry handler to use
* @returns A TaskOptions instance configured with the retry handler
*
* @example
* ```typescript
* const handler: AsyncRetryHandler = async (context) => {
* if (context.lastAttemptNumber >= 5) return false;
* if (context.lastFailure.errorType === "ValidationError") return false;
* return true;
* };
*
* const options = taskOptionsFromRetryHandler(handler);
* await ctx.callActivity("myActivity", input, options);
* ```
*/
export function taskOptionsFromRetryHandler(handler: AsyncRetryHandler): TaskOptions {
return { retry: handler };
}

/**
* Creates a TaskOptions instance from a synchronous RetryHandler.
*
* @param handler - The sync retry handler to use (will be wrapped in a Promise)
* @returns A TaskOptions instance configured with the retry handler
*
* @example
* ```typescript
* const handler: RetryHandler = (context) => {
* return context.lastAttemptNumber < 3;
* };
*
* const options = taskOptionsFromSyncRetryHandler(handler);
* await ctx.callActivity("myActivity", input, options);
* ```
*/
export function taskOptionsFromSyncRetryHandler(handler: RetryHandler): TaskOptions {
return { retry: toAsyncRetryHandler(handler) };
}
Comment thread
YunchuWang marked this conversation as resolved.
Outdated

/**
* Creates a SubOrchestrationOptions instance from a RetryPolicy and optional instance ID.
*
Expand All @@ -104,3 +161,47 @@ export function subOrchestrationOptionsFromRetryPolicy(
): SubOrchestrationOptions {
return { retry: policy, instanceId };
}

/**
* Creates a SubOrchestrationOptions instance from an AsyncRetryHandler and optional instance ID.
*
* @param handler - The async retry handler to use
* @param instanceId - Optional instance ID for the sub-orchestration
* @returns A SubOrchestrationOptions instance configured with the retry handler
*
* @example
* ```typescript
* const handler: AsyncRetryHandler = async (context) => {
* return context.lastAttemptNumber < 3;
* };
*
* const options = subOrchestrationOptionsFromRetryHandler(handler, "my-sub-orch-123");
* ```
*/
export function subOrchestrationOptionsFromRetryHandler(
handler: AsyncRetryHandler,
instanceId?: string,
): SubOrchestrationOptions {
return { retry: handler, instanceId };
}

/**
* Type guard to check if the retry option is a RetryPolicy.
*
* @param retry - The retry option to check
* @returns true if the retry option is a RetryPolicy, false otherwise
*/
export function isRetryPolicy(retry: TaskRetryOptions | undefined): retry is RetryPolicy {
return retry instanceof RetryPolicy;
}

/**
* Type guard to check if the retry option is a retry handler function
* (either {@link AsyncRetryHandler} or {@link RetryHandler}).
*
* @param retry - The retry option to check
* @returns true if the retry option is a handler function, false otherwise
*/
export function isRetryHandler(retry: TaskRetryOptions | undefined): retry is AsyncRetryHandler | RetryHandler {
return typeof retry === "function";
}
Comment thread
YunchuWang marked this conversation as resolved.
Loading
Loading