diff --git a/packages/activity/src/index.ts b/packages/activity/src/index.ts index d9591ce09..4c780ea0d 100644 --- a/packages/activity/src/index.ts +++ b/packages/activity/src/index.ts @@ -79,6 +79,7 @@ import { Priority, ActivityCancellationDetails, IllegalStateError, + RetryPolicy, } from '@temporalio/common'; import { msToNumber } from '@temporalio/common/lib/time'; import { SymbolBasedInstanceOfError } from '@temporalio/common/lib/type-helpers'; @@ -213,6 +214,14 @@ export interface Info { * Priority of this activity */ readonly priority?: Priority; + /** + * The retry policy of this activity. + * + * Note that the server may have set a different policy than the one provided when scheduling the activity. + * If the value is undefined, it means the server didn't send information about retry policy (e.g. due to old server + * version), but it may still be defined server-side. + */ + readonly retryPolicy?: RetryPolicy; } /** diff --git a/packages/test/src/test-local-activities.ts b/packages/test/src/test-local-activities.ts index 10f4de2bc..ae73518b9 100644 --- a/packages/test/src/test-local-activities.ts +++ b/packages/test/src/test-local-activities.ts @@ -9,7 +9,7 @@ import { WorkflowHandle, WorkflowStartOptions, } from '@temporalio/client'; -import { LocalActivityOptions } from '@temporalio/common'; +import { LocalActivityOptions, RetryPolicy } from '@temporalio/common'; import { msToNumber } from '@temporalio/common/lib/time'; import { temporal } from '@temporalio/proto'; import { workflowInterceptorModules } from '@temporalio/testing'; @@ -624,3 +624,36 @@ export const interceptors: workflow.WorkflowInterceptorsFactory = () => { ], }; }; + +export async function getRetryPolicyFromActivityInfo( + retryPolicy: RetryPolicy, + fromInsideLocal: boolean +): Promise { + return await (fromInsideLocal + ? workflow.proxyLocalActivities({ startToCloseTimeout: '1m', retry: retryPolicy }).retryPolicy() + : workflow.proxyActivities({ startToCloseTimeout: '1m', retry: retryPolicy }).retryPolicy()); +} + +test.serial('retryPolicy is set correctly', async (t) => { + const { executeWorkflow, createWorker } = helpers(t); + const worker = await createWorker({ + activities: { + async retryPolicy(): Promise { + return ActivityContext.current().info.retryPolicy; + }, + }, + }); + + const retryPolicy: RetryPolicy = { + backoffCoefficient: 1.5, + initialInterval: 2.0, + maximumAttempts: 3, + maximumInterval: 10.0, + nonRetryableErrorTypes: ['nonRetryableError'], + }; + + await worker.runUntil(async () => { + t.deepEqual(await executeWorkflow(getRetryPolicyFromActivityInfo, { args: [retryPolicy, true] }), retryPolicy); + t.deepEqual(await executeWorkflow(getRetryPolicyFromActivityInfo, { args: [retryPolicy, false] }), retryPolicy); + }); +}); diff --git a/packages/testing/src/mocking-activity-environment.ts b/packages/testing/src/mocking-activity-environment.ts index cc6aaa531..eaae7b0ad 100644 --- a/packages/testing/src/mocking-activity-environment.ts +++ b/packages/testing/src/mocking-activity-environment.ts @@ -96,4 +96,5 @@ export const defaultActivityInfo: activity.Info = { scheduleToCloseTimeoutMs: 1000, currentAttemptScheduledTimestampMs: 1, priority: undefined, + retryPolicy: undefined, }; diff --git a/packages/worker/src/worker.ts b/packages/worker/src/worker.ts index 9a949235d..47a392d94 100644 --- a/packages/worker/src/worker.ts +++ b/packages/worker/src/worker.ts @@ -2132,6 +2132,7 @@ async function extractActivityInfo( 'currentAttemptScheduledTime' ), priority: decodePriority(start.priority), + retryPolicy: decompileRetryPolicy(start.retryPolicy), }; }