Skip to content

Commit a8d4a69

Browse files
committed
Options getter function
1 parent e59e2d0 commit a8d4a69

File tree

6 files changed

+51
-13
lines changed

6 files changed

+51
-13
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
@@ -10,8 +10,9 @@ import { Client } from '@temporalio/client';
1010
import { toCanonicalString, WorkerDeploymentVersion } from '@temporalio/common';
1111
import { temporal } from '@temporalio/proto';
1212
import { Worker } from './helpers';
13-
import { makeTestFunction } from './helpers-integration';
13+
import { Context, makeTestFunction } from './helpers-integration';
1414
import { unblockSignal, versionQuery } from './workflows';
15+
import { ExecutionContext } from 'ava';
1516

1617
const test = makeTestFunction({ workflowsPath: __filename });
1718

@@ -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

+10-2
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,18 @@ export function initRuntime(options: WorkflowCreateOptionsInternal): void {
8686

8787
if (isWorkflowFunctionWithOptions(workflowFn)) {
8888
activator.workflow = workflowFn;
89-
activator.versioningBehavior = workflowFn.options.versioningBehavior;
89+
if (typeof workflowFn.options === 'object') {
90+
activator.versioningBehavior = workflowFn.options.versioningBehavior;
91+
} else {
92+
activator.workflowDefinitionOptionsGetter = workflowFn.options;
93+
}
9094
} else if (isWorkflowFunctionWithOptions(defaultWorkflowFn)) {
9195
activator.workflow = defaultWorkflowFn;
92-
activator.versioningBehavior = defaultWorkflowFn.options.versioningBehavior;
96+
if (typeof defaultWorkflowFn.options === 'object') {
97+
activator.versioningBehavior = defaultWorkflowFn.options.versioningBehavior;
98+
} else {
99+
activator.workflowDefinitionOptionsGetter = defaultWorkflowFn.options;
100+
}
93101
} else if (typeof workflowFn === 'function') {
94102
activator.workflow = workflowFn;
95103
} 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)