Skip to content

Commit f18b1ca

Browse files
committed
Options getter function
1 parent e59e2d0 commit f18b1ca

File tree

6 files changed

+53
-20
lines changed

6 files changed

+53
-20
lines changed

packages/common/src/workflow-definition-options.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ export interface WorkflowDefinitionOptions {
88
}
99

1010
type AsyncFunction<Args extends any[], ReturnType> = (...args: Args) => Promise<ReturnType>;
11+
export type WorkflowDefinitionOptionsOrGetter = WorkflowDefinitionOptions | (() => WorkflowDefinitionOptions);
1112

1213
/**
1314
* A workflow function that has been defined with options from {@link WorkflowDefinitionOptions}.
1415
*/
1516
export interface WorkflowFunctionWithOptions<Args extends any[], ReturnType> extends AsyncFunction<Args, ReturnType> {
1617
__temporal_is_workflow_function_with_options: true;
17-
options: WorkflowDefinitionOptions;
18+
options: WorkflowDefinitionOptionsOrGetter;
1819
}

packages/test/src/deployment-versioning-v1/index.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { setHandler, condition, defineWorkflowWithOptions } from '@temporalio/workflow';
1+
import { setHandler, condition, defineWorkflowWithOptions, workflowInfo } from '@temporalio/workflow';
22
import { unblockSignal, versionQuery } from '../workflows';
33

44
defineWorkflowWithOptions({ versioningBehavior: 'AUTO_UPGRADE' }, deploymentVersioning);
@@ -15,3 +15,14 @@ export default defineWorkflowWithOptions({ versioningBehavior: 'PINNED' }, _defa
1515
async function _default(): Promise<string> {
1616
return 'dynamic';
1717
}
18+
19+
defineWorkflowWithOptions(() => {
20+
// Need to ensure accessing workflow context still works in here
21+
workflowInfo();
22+
return {
23+
versioningBehavior: 'PINNED',
24+
};
25+
}, usesGetter);
26+
export async function usesGetter(): Promise<string> {
27+
return 'usesGetter';
28+
}

packages/test/src/test-worker-deployment-versioning.ts

+17-6
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
import assert from 'assert';
77
import { randomUUID } from 'crypto';
88
import asyncRetry from 'async-retry';
9+
import { ExecutionContext } from 'ava';
910
import { Client } from '@temporalio/client';
1011
import { toCanonicalString, WorkerDeploymentVersion } from '@temporalio/common';
1112
import { temporal } from '@temporalio/proto';
1213
import { Worker } from './helpers';
13-
import { makeTestFunction } from './helpers-integration';
14+
import { Context, makeTestFunction } from './helpers-integration';
1415
import { unblockSignal, versionQuery } from './workflows';
1516

1617
const test = makeTestFunction({ workflowsPath: __filename });
@@ -242,7 +243,11 @@ test('Worker deployment based versioning with ramping', async (t) => {
242243
t.pass();
243244
});
244245

245-
test('Worker deployment with dynamic workflow on run', async (t) => {
246+
async function testWorkerDeploymentWithDynamicBehavior(
247+
t: ExecutionContext<Context>,
248+
workflowName: string,
249+
expectedResult: string
250+
) {
246251
if (t.context.env.supportsTimeSkipping) {
247252
t.pass("Test Server doesn't support worker deployments");
248253
return;
@@ -276,17 +281,15 @@ test('Worker deployment with dynamic workflow on run', async (t) => {
276281
const describeResp = await waitUntilWorkerDeploymentVisible(client, version);
277282
await setCurrentDeploymentVersion(client, describeResp.conflictToken, version);
278283

279-
const wf = await client.workflow.start('cooldynamicworkflow', {
284+
const wf = await client.workflow.start(workflowName, {
280285
taskQueue,
281286
workflowId: 'dynamic-workflow-versioning-' + randomUUID(),
282287
});
283288

284289
const result = await wf.result();
285-
assert.equal(result, 'dynamic');
290+
assert.equal(result, expectedResult);
286291

287-
// Check history for versioning behavior
288292
const history = await wf.fetchHistory();
289-
290293
const hasPinnedVersioningBehavior = history.events!.some(
291294
(event) =>
292295
event.workflowTaskCompletedEventAttributes &&
@@ -298,6 +301,14 @@ test('Worker deployment with dynamic workflow on run', async (t) => {
298301
worker.shutdown();
299302
await workerPromise;
300303
t.pass();
304+
}
305+
306+
test('Worker deployment with dynamic workflow static behavior', async (t) => {
307+
await testWorkerDeploymentWithDynamicBehavior(t, 'cooldynamicworkflow', 'dynamic');
308+
});
309+
310+
test('Worker deployment with behavior in getter', async (t) => {
311+
await testWorkerDeploymentWithDynamicBehavior(t, 'usesGetter', 'usesGetter');
301312
});
302313

303314
test('Workflows can use default versioning behavior', async (t) => {

packages/workflow/src/internals.ts

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
fromPayloadsAtIndex,
2323
WorkflowFunctionWithOptions,
2424
VersioningBehavior,
25+
WorkflowDefinitionOptions,
2526
} from '@temporalio/common';
2627
import {
2728
decodeSearchAttributes,
@@ -419,6 +420,7 @@ export class Activator implements ActivationHandler {
419420
public readonly registeredActivityNames: Set<string>;
420421

421422
public versioningBehavior?: VersioningBehavior;
423+
public workflowDefinitionOptionsGetter?: () => WorkflowDefinitionOptions;
422424

423425
constructor({
424426
info,
@@ -534,6 +536,9 @@ export class Activator implements ActivationHandler {
534536
? this.failureConverter.failureToError(continuedFailure, this.payloadConverter)
535537
: undefined,
536538
}));
539+
if (this.workflowDefinitionOptionsGetter) {
540+
this.versioningBehavior = this.workflowDefinitionOptionsGetter().versioningBehavior;
541+
}
537542
}
538543

539544
public cancelWorkflow(_activation: coresdk.workflow_activation.ICancelWorkflow): void {

packages/workflow/src/worker-interface.ts

+12-9
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,9 @@
33
*
44
* @module
55
*/
6-
import {
7-
encodeVersioningBehavior,
8-
IllegalStateError,
9-
isWorkflowFunctionWithOptions,
10-
VersioningBehavior,
11-
} from '@temporalio/common';
6+
import { encodeVersioningBehavior, IllegalStateError, isWorkflowFunctionWithOptions } from '@temporalio/common';
127
import { composeInterceptors } from '@temporalio/common/lib/interceptors';
13-
import { coresdk, temporal } from '@temporalio/proto';
8+
import { coresdk } from '@temporalio/proto';
149
import { disableStorage } from './cancellation-scope';
1510
import { disableUpdateStorage } from './update-scope';
1611
import { WorkflowInterceptorsFactory } from './interceptors';
@@ -86,10 +81,18 @@ export function initRuntime(options: WorkflowCreateOptionsInternal): void {
8681

8782
if (isWorkflowFunctionWithOptions(workflowFn)) {
8883
activator.workflow = workflowFn;
89-
activator.versioningBehavior = workflowFn.options.versioningBehavior;
84+
if (typeof workflowFn.options === 'object') {
85+
activator.versioningBehavior = workflowFn.options.versioningBehavior;
86+
} else {
87+
activator.workflowDefinitionOptionsGetter = workflowFn.options;
88+
}
9089
} else if (isWorkflowFunctionWithOptions(defaultWorkflowFn)) {
9190
activator.workflow = defaultWorkflowFn;
92-
activator.versioningBehavior = defaultWorkflowFn.options.versioningBehavior;
91+
if (typeof defaultWorkflowFn.options === 'object') {
92+
activator.versioningBehavior = defaultWorkflowFn.options.versioningBehavior;
93+
} else {
94+
activator.workflowDefinitionOptionsGetter = defaultWorkflowFn.options;
95+
}
9396
} else if (typeof workflowFn === 'function') {
9497
activator.workflow = workflowFn;
9598
} else if (typeof defaultWorkflowFn === 'function') {

packages/workflow/src/workflow.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
WorkflowUpdateValidatorType,
2424
SearchAttributeUpdatePair,
2525
compilePriority,
26-
WorkflowDefinitionOptions,
26+
WorkflowDefinitionOptionsOrGetter,
2727
WorkflowFunctionWithOptions,
2828
} from '@temporalio/common';
2929
import {
@@ -1617,13 +1617,15 @@ export function allHandlersFinished(): boolean {
16171617
* }
16181618
* ```
16191619
*
1620-
* @param options Options for the workflow defintion.
1620+
* @param options Options for the workflow defintion, or a function that returns options. If a
1621+
* function is provided, it will be called once just before the workflow function is called for the
1622+
* first time.
16211623
* @param fn The workflow function.
16221624
* @returns The same passed in workflow function, with the specified options applied. You can export
16231625
* this function to make it available as a workflow function.
16241626
*/
16251627
export function defineWorkflowWithOptions<A extends any[], RT>(
1626-
options: WorkflowDefinitionOptions,
1628+
options: WorkflowDefinitionOptionsOrGetter,
16271629
fn: (...args: A) => Promise<RT>
16281630
): WorkflowFunctionWithOptions<A, RT> {
16291631
const wrappedFn = Object.assign(fn, {

0 commit comments

Comments
 (0)