Skip to content

Worker Deployment Versioning #1679

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export * from './logger';
export * from './priority';
export * from './retry-policy';
export type { Timestamp, Duration, StringValue } from './time';
export * from './worker-deployments';
export * from './workflow-definition-options';
export * from './workflow-handle';
export * from './workflow-options';
export * from './versioning-intent';
Expand Down
50 changes: 50 additions & 0 deletions packages/common/src/worker-deployments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { temporal } from '@temporalio/proto';
import { makeProtoEnumConverters } from './internal-workflow';

/**
* Represents the version of a specific worker deployment.
*
* @experimental Deployment based versioning is experimental and may change in the future.
*/
export interface WorkerDeploymentVersion {
readonly buildId: string;
readonly deploymentName: string;
}

/**
* @returns The canonical representation of a deployment version, which is a string in the format
* `deploymentName.buildId`.
*/
export function toCanonicalString(version: WorkerDeploymentVersion): string {
return `${version.deploymentName}.${version.buildId}`;
}

/**
* Specifies when a workflow might move from a worker of one Build Id to another.
*
* * 'pinned' - The workflow will be pinned to the current Build ID unless manually moved.
* * 'auto-upgrade' - The workflow will automatically move to the latest version (default Build ID
* of the task queue) when the next task is dispatched.
*
* @experimental Deployment based versioning is experimental and may change in the future.
*/
export const VersioningBehavior = {
PINNED: 'PINNED',
AUTO_UPGRADE: 'AUTO_UPGRADE',
} as const;
export type VersioningBehavior = (typeof VersioningBehavior)[keyof typeof VersioningBehavior];

export const [encodeVersioningBehavior, decodeVersioningBehavior] = makeProtoEnumConverters<
temporal.api.enums.v1.VersioningBehavior,
typeof temporal.api.enums.v1.VersioningBehavior,
keyof typeof temporal.api.enums.v1.VersioningBehavior,
typeof VersioningBehavior,
'VERSIONING_BEHAVIOR_'
>(
{
[VersioningBehavior.PINNED]: 1,
[VersioningBehavior.AUTO_UPGRADE]: 2,
UNSPECIFIED: 0,
} as const,
'VERSIONING_BEHAVIOR_'
);
19 changes: 19 additions & 0 deletions packages/common/src/workflow-definition-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { VersioningBehavior } from './worker-deployments';

/**
* Options that can be used when defining a workflow via {@link defineWorkflowWithOptions}.
*/
export interface WorkflowDefinitionOptions {
versioningBehavior?: VersioningBehavior;
}

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

/**
* A workflow function that has been defined with options from {@link WorkflowDefinitionOptions}.
*/
export interface WorkflowFunctionWithOptions<Args extends any[], ReturnType> extends AsyncFunction<Args, ReturnType> {
__temporal_is_workflow_function_with_options: true;
options: WorkflowDefinitionOptionsOrGetter;
}
11 changes: 10 additions & 1 deletion packages/common/src/workflow-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Duration } from './time';
import { makeProtoEnumConverters } from './internal-workflow';
import { SearchAttributePair, SearchAttributes, TypedSearchAttributes } from './search-attributes';
import { Priority } from './priority';
import { WorkflowFunctionWithOptions } from './workflow-definition-options';

/**
* Defines what happens when trying to start a Workflow with the same ID as a *Closed* Workflow.
Expand Down Expand Up @@ -243,7 +244,9 @@ export interface WorkflowDurationOptions {

export type CommonWorkflowOptions = BaseWorkflowOptions & WorkflowDurationOptions;

export function extractWorkflowType<T extends Workflow>(workflowTypeOrFunc: string | T): string {
export function extractWorkflowType<T extends Workflow>(
workflowTypeOrFunc: string | T | WorkflowFunctionWithOptions<any[], any>
): string {
if (typeof workflowTypeOrFunc === 'string') return workflowTypeOrFunc as string;
if (typeof workflowTypeOrFunc === 'function') {
if (workflowTypeOrFunc?.name) return workflowTypeOrFunc.name;
Expand All @@ -253,3 +256,9 @@ export function extractWorkflowType<T extends Workflow>(workflowTypeOrFunc: stri
`Invalid workflow type: expected either a string or a function, got '${typeof workflowTypeOrFunc}'`
);
}

/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
export function isWorkflowFunctionWithOptions(obj: any): obj is WorkflowFunctionWithOptions<any[], any> {
if (obj == null) return false;
return obj.__temporal_is_workflow_function_with_options === true;
}
Loading
Loading