@temporalio/client
Advanced tools
Comparing version 1.11.5 to 1.11.6
@@ -40,4 +40,4 @@ import { DataConverter, LoadedDataConverter } from '@temporalio/common'; | ||
* | ||
* Clients are cheap to create, but connections are expensive. Where that make sense, | ||
* a single connection may and should be reused by multiple `Client`. | ||
* Clients are cheap to create, but connections are expensive. Where it makes sense, | ||
* a single connection may and should be reused by multiple `Client`s. | ||
*/ | ||
@@ -44,0 +44,0 @@ readonly connection: ConnectionLike; |
import { ServiceError as GrpcServiceError } from '@grpc/grpc-js'; | ||
import { LoadedDataConverter } from '@temporalio/common'; | ||
import { Replace } from '@temporalio/common/lib/type-helpers'; | ||
import { RawWorkflowExecutionInfo, WorkflowExecutionInfo } from './types'; | ||
import { temporal } from '@temporalio/proto'; | ||
import { CountWorkflowExecution, RawWorkflowExecutionInfo, WorkflowExecutionInfo } from './types'; | ||
export declare function executionInfoFromRaw<T>(raw: RawWorkflowExecutionInfo, dataConverter: LoadedDataConverter, rawDataToEmbed: T): Promise<Replace<WorkflowExecutionInfo, { | ||
raw: T; | ||
}>>; | ||
export declare function decodeCountWorkflowExecutionsResponse(raw: temporal.api.workflowservice.v1.ICountWorkflowExecutionsResponse): CountWorkflowExecution; | ||
/** | ||
@@ -9,0 +11,0 @@ * If the error type can be determined based on embedded grpc error details, |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.executionInfoFromRaw = executionInfoFromRaw; | ||
exports.decodeCountWorkflowExecutionsResponse = decodeCountWorkflowExecutionsResponse; | ||
exports.rethrowKnownErrorTypes = rethrowKnownErrorTypes; | ||
const grpc_js_1 = require("@grpc/grpc-js"); | ||
const common_1 = require("@temporalio/common"); | ||
@@ -66,2 +68,15 @@ const time_1 = require("@temporalio/common/lib/time"); | ||
} | ||
function decodeCountWorkflowExecutionsResponse(raw) { | ||
return { | ||
// Note: lossy conversion of Long to number | ||
count: raw.count.toNumber(), | ||
groups: raw.groups.map((group) => { | ||
return { | ||
// Note: lossy conversion of Long to number | ||
count: group.count.toNumber(), | ||
groupValues: group.groupValues.map((value) => common_1.searchAttributePayloadConverter.fromPayload(value)), | ||
}; | ||
}), | ||
}; | ||
} | ||
/** | ||
@@ -86,2 +101,22 @@ * If the error type can be determined based on embedded grpc error details, | ||
} | ||
case 'temporal.api.errordetails.v1.MultiOperationExecutionFailure': { | ||
// MultiOperationExecutionFailure contains error statuses for multiple | ||
// operations. A MultiOperationExecutionAborted error status means that | ||
// the corresponding operation was aborted due to an error in one of the | ||
// other operations. We rethrow the first operation error that is not | ||
// MultiOperationExecutionAborted. | ||
const { statuses } = proto_1.temporal.api.errordetails.v1.MultiOperationExecutionFailure.decode(entry.value); | ||
for (const status of statuses) { | ||
const detail = status.details?.[0]; | ||
const statusType = detail?.type_url?.replace(/^type.googleapis.com\//, ''); | ||
if (statusType === 'temporal.api.failure.v1.MultiOperationExecutionAborted' || | ||
status.code === grpc_js_1.status.OK) { | ||
continue; | ||
} | ||
err.message = status.message ?? err.message; | ||
err.code = status.code || err.code; | ||
err.details = detail?.value?.toString() || err.details; | ||
throw err; | ||
} | ||
} | ||
} | ||
@@ -88,0 +123,0 @@ } |
@@ -34,2 +34,26 @@ /** | ||
} | ||
/** | ||
* Input for WorkflowClientInterceptor.startUpdateWithStart | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
export interface WorkflowStartUpdateWithStartInput { | ||
readonly workflowType: string; | ||
readonly workflowStartOptions: CompiledWorkflowOptions; | ||
readonly workflowStartHeaders: Headers; | ||
readonly updateName: string; | ||
readonly updateArgs: unknown[]; | ||
readonly updateOptions: WorkflowUpdateOptions; | ||
readonly updateHeaders: Headers; | ||
} | ||
/** | ||
* Output for WorkflowClientInterceptor.startUpdateWithStart | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
export interface WorkflowStartUpdateWithStartOutput { | ||
readonly workflowExecution: WorkflowExecution; | ||
readonly updateId: string; | ||
readonly updateOutcome?: temporal.api.update.v1.IOutcome; | ||
} | ||
/** Input for WorkflowClientInterceptor.signal */ | ||
@@ -87,7 +111,11 @@ export interface WorkflowSignalInput { | ||
* Intercept a service call to updateWorkflowExecution | ||
* | ||
* @experimental Update is an experimental feature. | ||
*/ | ||
startUpdate?: (input: WorkflowStartUpdateInput, next: Next<this, 'startUpdate'>) => Promise<WorkflowStartUpdateOutput>; | ||
/** | ||
* Intercept a service call to startUpdateWithStart | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
startUpdateWithStart?: (input: WorkflowStartUpdateWithStartInput, next: Next<this, 'startUpdateWithStart'>) => Promise<WorkflowStartUpdateWithStartOutput>; | ||
/** | ||
* Intercept a service call to signalWorkflowExecution | ||
@@ -94,0 +122,0 @@ * |
import type * as grpc from '@grpc/grpc-js'; | ||
import type { SearchAttributes } from '@temporalio/common'; | ||
import type { SearchAttributes, SearchAttributeValue } from '@temporalio/common'; | ||
import * as proto from '@temporalio/proto'; | ||
@@ -40,2 +40,9 @@ import { Replace } from '@temporalio/common/lib/type-helpers'; | ||
} | ||
export interface CountWorkflowExecution { | ||
count: number; | ||
groups: { | ||
count: number; | ||
groupValues: SearchAttributeValue[]; | ||
}[]; | ||
} | ||
export type WorkflowExecutionDescription = Replace<WorkflowExecutionInfo, { | ||
@@ -42,0 +49,0 @@ raw: DescribeWorkflowExecutionResponse; |
import { status as grpcStatus } from '@grpc/grpc-js'; | ||
import { BaseWorkflowHandle, HistoryAndWorkflowId, QueryDefinition, UpdateDefinition, WithWorkflowArgs, Workflow, WorkflowResultType } from '@temporalio/common'; | ||
import { BaseWorkflowHandle, HistoryAndWorkflowId, QueryDefinition, UpdateDefinition, WithWorkflowArgs, Workflow, WorkflowResultType, WorkflowIdConflictPolicy } from '@temporalio/common'; | ||
import { History } from '@temporalio/common/lib/proto-utils'; | ||
import { temporal } from '@temporalio/proto'; | ||
import { WorkflowCancelInput, WorkflowClientInterceptor, WorkflowClientInterceptors, WorkflowDescribeInput, WorkflowQueryInput, WorkflowSignalInput, WorkflowSignalWithStartInput, WorkflowStartInput, WorkflowTerminateInput, WorkflowStartUpdateInput, WorkflowStartUpdateOutput } from './interceptors'; | ||
import { DescribeWorkflowExecutionResponse, QueryRejectCondition, RequestCancelWorkflowExecutionResponse, TerminateWorkflowExecutionResponse, WorkflowExecution, WorkflowExecutionDescription, WorkflowExecutionInfo, WorkflowService } from './types'; | ||
import { WorkflowCancelInput, WorkflowClientInterceptor, WorkflowClientInterceptors, WorkflowDescribeInput, WorkflowQueryInput, WorkflowSignalInput, WorkflowSignalWithStartInput, WorkflowStartInput, WorkflowTerminateInput, WorkflowStartUpdateInput, WorkflowStartUpdateOutput, WorkflowStartUpdateWithStartInput, WorkflowStartUpdateWithStartOutput } from './interceptors'; | ||
import { CountWorkflowExecution, DescribeWorkflowExecutionResponse, QueryRejectCondition, RequestCancelWorkflowExecutionResponse, StartWorkflowExecutionRequest, TerminateWorkflowExecutionResponse, WorkflowExecution, WorkflowExecutionDescription, WorkflowExecutionInfo, WorkflowService } from './types'; | ||
import { WorkflowOptions, WorkflowSignalWithStartOptions, WorkflowStartOptions, WorkflowUpdateOptions } from './workflow-options'; | ||
@@ -44,4 +44,2 @@ import { BaseClient, BaseClientOptions, LoadedWithDefaults } from './base-client'; | ||
* | ||
* @experimental Update is an experimental feature. | ||
* | ||
* @throws {@link WorkflowUpdateFailedError} if Update validation fails or if ApplicationFailure is thrown in the Update handler. | ||
@@ -68,4 +66,2 @@ * @throws {@link WorkflowUpdateRPCTimeoutOrCancelledError} if this Update call timed out or was cancelled. This doesn't | ||
* | ||
* @experimental Update is an experimental feature. | ||
* | ||
* @throws {@link WorkflowUpdateFailedError} if Update validation fails. | ||
@@ -311,3 +307,26 @@ * @throws {@link WorkflowUpdateRPCTimeoutOrCancelledError} if this Update call timed out or was cancelled. This doesn't | ||
} | ||
declare const withStartWorkflowOperationResolve: unique symbol; | ||
declare const withStartWorkflowOperationReject: unique symbol; | ||
declare const withStartWorkflowOperationUsed: unique symbol; | ||
/** | ||
* Define how to start a workflow when using {@link WorkflowClient.startUpdateWithStart} and | ||
* {@link WorkflowClient.executeUpdateWithStart}. `workflowIdConflictPolicy` is required in the options. | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
export declare class WithStartWorkflowOperation<T extends Workflow> { | ||
workflowTypeOrFunc: string | T; | ||
options: WorkflowStartOptions<T> & { | ||
workflowIdConflictPolicy: WorkflowIdConflictPolicy; | ||
}; | ||
private [withStartWorkflowOperationUsed]; | ||
private [withStartWorkflowOperationResolve]; | ||
private [withStartWorkflowOperationReject]; | ||
private workflowHandlePromise; | ||
constructor(workflowTypeOrFunc: string | T, options: WorkflowStartOptions<T> & { | ||
workflowIdConflictPolicy: WorkflowIdConflictPolicy; | ||
}); | ||
workflowHandle(): Promise<WorkflowHandle<T>>; | ||
} | ||
/** | ||
* Client for starting Workflow executions and creating Workflow handles. | ||
@@ -328,30 +347,83 @@ * | ||
get workflowService(): WorkflowService; | ||
protected _start<T extends Workflow>(workflowTypeOrFunc: string | T, options: WithWorkflowArgs<T, WorkflowOptions>, interceptors: WorkflowClientInterceptor[]): Promise<string>; | ||
protected _signalWithStart<T extends Workflow, SA extends any[]>(workflowTypeOrFunc: string | T, options: WithWorkflowArgs<T, WorkflowSignalWithStartOptions<SA>>, interceptors: WorkflowClientInterceptor[]): Promise<string>; | ||
/** | ||
* Start a new Workflow execution. | ||
* | ||
* @returns the execution's `runId`. | ||
* @returns a {@link WorkflowHandle} to the started Workflow | ||
*/ | ||
protected _start<T extends Workflow>(workflowTypeOrFunc: string | T, options: WithWorkflowArgs<T, WorkflowOptions>, interceptors: WorkflowClientInterceptor[]): Promise<string>; | ||
start<T extends Workflow>(workflowTypeOrFunc: string | T, options: WorkflowStartOptions<T>): Promise<WorkflowHandleWithFirstExecutionRunId<T>>; | ||
/** | ||
* Sends a signal to a running Workflow or starts a new one if not already running and immediately signals it. | ||
* Useful when you're unsure of the Workflow's run state. | ||
* Start a new Workflow Execution and immediately send a Signal to that Workflow. | ||
* | ||
* @returns the runId of the Workflow | ||
* The behavior of Signal-with-Start in the case where there is already a running Workflow with | ||
* the given Workflow ID depends on the {@link WorkflowIDConflictPolicy}. That is, if the policy | ||
* is `USE_EXISTING`, then the Signal is issued against the already existing Workflow Execution; | ||
* however, if the policy is `FAIL`, then an error is thrown. If no policy is specified, | ||
* Signal-with-Start defaults to `USE_EXISTING`. | ||
* | ||
* @returns a {@link WorkflowHandle} to the started Workflow | ||
*/ | ||
protected _signalWithStart<T extends Workflow, SA extends any[]>(workflowTypeOrFunc: string | T, options: WithWorkflowArgs<T, WorkflowSignalWithStartOptions<SA>>, interceptors: WorkflowClientInterceptor[]): Promise<string>; | ||
signalWithStart<WorkflowFn extends Workflow, SignalArgs extends any[] = []>(workflowTypeOrFunc: string | WorkflowFn, options: WithWorkflowArgs<WorkflowFn, WorkflowSignalWithStartOptions<SignalArgs>>): Promise<WorkflowHandleWithSignaledRunId<WorkflowFn>>; | ||
/** | ||
* Start a new Workflow execution. | ||
* Start a new Workflow Execution and immediately send an Update to that Workflow, | ||
* then await and return the Update's result. | ||
* | ||
* @returns a WorkflowHandle to the started Workflow | ||
* The `updateOptions` object must contain a {@link WithStartWorkflowOperation}, which defines | ||
* the options for the Workflow execution to start (e.g. the Workflow's type, task queue, input | ||
* arguments, etc.) | ||
* | ||
* The behavior of Update-with-Start in the case where there is already a running Workflow with | ||
* the given Workflow ID depends on the specified {@link WorkflowIDConflictPolicy}. That is, if | ||
* the policy is `USE_EXISTING`, then the Update is issued against the already existing Workflow | ||
* Execution; however, if the policy is `FAIL`, then an error is thrown. Caller MUST specify | ||
* the desired WorkflowIDConflictPolicy. | ||
* | ||
* This call will block until the Update has completed. The Workflow handle can be retrieved by | ||
* awaiting on {@link WithStartWorkflowOperation.workflowHandle}, whether or not the Update | ||
* succeeds. | ||
* | ||
* @returns the Update result | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
start<T extends Workflow>(workflowTypeOrFunc: string | T, options: WorkflowStartOptions<T>): Promise<WorkflowHandleWithFirstExecutionRunId<T>>; | ||
executeUpdateWithStart<T extends Workflow, Ret, Args extends any[]>(updateDef: UpdateDefinition<Ret, Args> | string, updateOptions: WorkflowUpdateOptions & { | ||
args?: Args; | ||
startWorkflowOperation: WithStartWorkflowOperation<T>; | ||
}): Promise<Ret>; | ||
/** | ||
* Sends a Signal to a running Workflow or starts a new one if not already running and immediately Signals it. | ||
* Useful when you're unsure whether the Workflow has been started. | ||
* Start a new Workflow Execution and immediately send an Update to that Workflow, | ||
* then return a {@link WorkflowUpdateHandle} for that Update. | ||
* | ||
* @returns a {@link WorkflowHandle} to the started Workflow | ||
* The `updateOptions` object must contain a {@link WithStartWorkflowOperation}, which defines | ||
* the options for the Workflow execution to start (e.g. the Workflow's type, task queue, input | ||
* arguments, etc.) | ||
* | ||
* The behavior of Update-with-Start in the case where there is already a running Workflow with | ||
* the given Workflow ID depends on the specified {@link WorkflowIDConflictPolicy}. That is, if | ||
* the policy is `USE_EXISTING`, then the Update is issued against the already existing Workflow | ||
* Execution; however, if the policy is `FAIL`, then an error is thrown. Caller MUST specify | ||
* the desired WorkflowIDConflictPolicy. | ||
* | ||
* This call will block until the Update has reached the specified {@link WorkflowUpdateStage}. | ||
* Note that this means that the call will not return successfully until the Update has | ||
* been delivered to a Worker. The Workflow handle can be retrieved by awaiting on | ||
* {@link WithStartWorkflowOperation.workflowHandle}, whether or not the Update succeeds. | ||
* | ||
* @returns a {@link WorkflowUpdateHandle} to the started Update | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
signalWithStart<WorkflowFn extends Workflow, SignalArgs extends any[] = []>(workflowTypeOrFunc: string | WorkflowFn, options: WithWorkflowArgs<WorkflowFn, WorkflowSignalWithStartOptions<SignalArgs>>): Promise<WorkflowHandleWithSignaledRunId<WorkflowFn>>; | ||
startUpdateWithStart<T extends Workflow, Ret, Args extends any[]>(updateDef: UpdateDefinition<Ret, Args> | string, updateOptions: WorkflowUpdateOptions & { | ||
args?: Args; | ||
waitForStage: 'ACCEPTED'; | ||
startWorkflowOperation: WithStartWorkflowOperation<T>; | ||
}): Promise<WorkflowUpdateHandle<Ret>>; | ||
protected _startUpdateWithStart<T extends Workflow, Ret, Args extends any[]>(updateDef: UpdateDefinition<Ret, Args> | string, updateWithStartOptions: WorkflowUpdateOptions & { | ||
args?: Args; | ||
waitForStage: WorkflowUpdateStage; | ||
startWorkflowOperation: WithStartWorkflowOperation<T>; | ||
}): Promise<WorkflowUpdateHandle<Ret>>; | ||
/** | ||
* Starts a new Workflow execution and awaits its completion. | ||
* Start a new Workflow execution, then await for its completion and return that Workflow's result. | ||
* | ||
@@ -362,5 +434,5 @@ * @returns the result of the Workflow execution | ||
/** | ||
* Gets the result of a Workflow execution. | ||
* Get the result of a Workflow execution. | ||
* | ||
* Follows the chain of execution in case Workflow continues as new, or has a cron schedule or retry policy. | ||
* Follow the chain of execution in case Workflow continues as new, or has a cron schedule or retry policy. | ||
*/ | ||
@@ -371,3 +443,3 @@ result<T extends Workflow>(workflowId: string, runId?: string, opts?: WorkflowResultOptions): Promise<WorkflowResultType<T>>; | ||
/** | ||
* Uses given input to make a queryWorkflow call to the service | ||
* Use given input to make a queryWorkflow call to the service | ||
* | ||
@@ -377,2 +449,3 @@ * Used as the final function of the query interceptor chain | ||
protected _queryWorkflowHandler(input: WorkflowQueryInput): Promise<unknown>; | ||
protected _createUpdateWorkflowRequest(lifecycleStage: temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage, input: WorkflowStartUpdateInput): Promise<temporal.api.workflowservice.v1.IUpdateWorkflowExecutionRequest>; | ||
/** | ||
@@ -384,2 +457,9 @@ * Start the Update. | ||
protected _startUpdateHandler(waitForStage: WorkflowUpdateStage, input: WorkflowStartUpdateInput): Promise<WorkflowStartUpdateOutput>; | ||
/** | ||
* Send the Update-With-Start MultiOperation request. | ||
* | ||
* Used as the final function of the interceptor chain during | ||
* startUpdateWithStart and executeUpdateWithStart. | ||
*/ | ||
protected _updateWithStartHandler(waitForStage: WorkflowUpdateStage, onStart: (startResponse: temporal.api.workflowservice.v1.IStartWorkflowExecutionResponse) => void, onStartError: (err: any) => void, input: WorkflowStartUpdateWithStartInput): Promise<WorkflowStartUpdateWithStartOutput>; | ||
protected createWorkflowUpdateHandle<Ret>(updateId: string, workflowId: string, workflowRunId?: string, outcome?: temporal.api.update.v1.IOutcome): WorkflowUpdateHandle<Ret>; | ||
@@ -392,3 +472,3 @@ /** | ||
/** | ||
* Uses given input to make a signalWorkflowExecution call to the service | ||
* Use given input to make a signalWorkflowExecution call to the service | ||
* | ||
@@ -399,3 +479,3 @@ * Used as the final function of the signal interceptor chain | ||
/** | ||
* Uses given input to make a signalWithStartWorkflowExecution call to the service | ||
* Use given input to make a signalWithStartWorkflowExecution call to the service | ||
* | ||
@@ -406,3 +486,3 @@ * Used as the final function of the signalWithStart interceptor chain | ||
/** | ||
* Uses given input to make startWorkflowExecution call to the service | ||
* Use given input to make startWorkflowExecution call to the service | ||
* | ||
@@ -412,4 +492,5 @@ * Used as the final function of the start interceptor chain | ||
protected _startWorkflowHandler(input: WorkflowStartInput): Promise<string>; | ||
protected createStartWorkflowRequest(input: WorkflowStartInput): Promise<StartWorkflowExecutionRequest>; | ||
/** | ||
* Uses given input to make terminateWorkflowExecution call to the service | ||
* Use given input to make terminateWorkflowExecution call to the service | ||
* | ||
@@ -456,5 +537,5 @@ * Used as the final function of the terminate interceptor chain | ||
/** | ||
* List workflows by given `query`. | ||
* Return a list of Workflow Executions matching the given `query`. | ||
* | ||
* ⚠️ To use advanced query functionality, as of the 1.18 server release, you must use Elasticsearch based visibility. | ||
* Note that the list of Workflow Executions returned is approximate and eventually consistent. | ||
* | ||
@@ -465,2 +546,12 @@ * More info on the concept of "visibility" and the query syntax on the Temporal documentation site: | ||
list(options?: ListOptions): AsyncWorkflowListIterable; | ||
/** | ||
* Return the number of Workflow Executions matching the given `query`. If no `query` is provided, then return the | ||
* total number of Workflow Executions for this namespace. | ||
* | ||
* Note that the number of Workflow Executions returned is approximate and eventually consistent. | ||
* | ||
* More info on the concept of "visibility" and the query syntax on the Temporal documentation site: | ||
* https://docs.temporal.io/visibility | ||
*/ | ||
count(query?: string): Promise<CountWorkflowExecution>; | ||
protected getOrMakeInterceptors(workflowId: string, runId?: string): WorkflowClientInterceptor[]; | ||
@@ -467,0 +558,0 @@ } |
@@ -8,4 +8,5 @@ "use strict"; | ||
}; | ||
var _a, _b, _c; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.QueryNotRegisteredError = exports.QueryRejectedError = exports.WorkflowClient = void 0; | ||
exports.QueryNotRegisteredError = exports.QueryRejectedError = exports.WorkflowClient = exports.WithStartWorkflowOperation = void 0; | ||
const grpc_js_1 = require("@grpc/grpc-js"); | ||
@@ -45,3 +46,30 @@ const uuid_1 = require("uuid"); | ||
} | ||
const withStartWorkflowOperationResolve = Symbol(); | ||
const withStartWorkflowOperationReject = Symbol(); | ||
const withStartWorkflowOperationUsed = Symbol(); | ||
/** | ||
* Define how to start a workflow when using {@link WorkflowClient.startUpdateWithStart} and | ||
* {@link WorkflowClient.executeUpdateWithStart}. `workflowIdConflictPolicy` is required in the options. | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
class WithStartWorkflowOperation { | ||
constructor(workflowTypeOrFunc, options) { | ||
this.workflowTypeOrFunc = workflowTypeOrFunc; | ||
this.options = options; | ||
this[_a] = false; | ||
this[_b] = undefined; | ||
this[_c] = undefined; | ||
this.workflowHandlePromise = new Promise((resolve, reject) => { | ||
this[withStartWorkflowOperationResolve] = resolve; | ||
this[withStartWorkflowOperationReject] = reject; | ||
}); | ||
} | ||
async workflowHandle() { | ||
return await this.workflowHandlePromise; | ||
} | ||
} | ||
exports.WithStartWorkflowOperation = WithStartWorkflowOperation; | ||
_a = withStartWorkflowOperationUsed, _b = withStartWorkflowOperationResolve, _c = withStartWorkflowOperationReject; | ||
/** | ||
* Client for starting Workflow executions and creating Workflow handles. | ||
@@ -70,7 +98,2 @@ * | ||
} | ||
/** | ||
* Start a new Workflow execution. | ||
* | ||
* @returns the execution's `runId`. | ||
*/ | ||
async _start(workflowTypeOrFunc, options, interceptors) { | ||
@@ -87,8 +110,2 @@ const workflowType = (0, common_1.extractWorkflowType)(workflowTypeOrFunc); | ||
} | ||
/** | ||
* Sends a signal to a running Workflow or starts a new one if not already running and immediately signals it. | ||
* Useful when you're unsure of the Workflow's run state. | ||
* | ||
* @returns the runId of the Workflow | ||
*/ | ||
async _signalWithStart(workflowTypeOrFunc, options, interceptors) { | ||
@@ -111,3 +128,3 @@ const workflowType = (0, common_1.extractWorkflowType)(workflowTypeOrFunc); | ||
* | ||
* @returns a WorkflowHandle to the started Workflow | ||
* @returns a {@link WorkflowHandle} to the started Workflow | ||
*/ | ||
@@ -132,5 +149,10 @@ async start(workflowTypeOrFunc, options) { | ||
/** | ||
* Sends a Signal to a running Workflow or starts a new one if not already running and immediately Signals it. | ||
* Useful when you're unsure whether the Workflow has been started. | ||
* Start a new Workflow Execution and immediately send a Signal to that Workflow. | ||
* | ||
* The behavior of Signal-with-Start in the case where there is already a running Workflow with | ||
* the given Workflow ID depends on the {@link WorkflowIDConflictPolicy}. That is, if the policy | ||
* is `USE_EXISTING`, then the Signal is issued against the already existing Workflow Execution; | ||
* however, if the policy is `FAIL`, then an error is thrown. If no policy is specified, | ||
* Signal-with-Start defaults to `USE_EXISTING`. | ||
* | ||
* @returns a {@link WorkflowHandle} to the started Workflow | ||
@@ -156,4 +178,98 @@ */ | ||
/** | ||
* Starts a new Workflow execution and awaits its completion. | ||
* Start a new Workflow Execution and immediately send an Update to that Workflow, | ||
* then await and return the Update's result. | ||
* | ||
* The `updateOptions` object must contain a {@link WithStartWorkflowOperation}, which defines | ||
* the options for the Workflow execution to start (e.g. the Workflow's type, task queue, input | ||
* arguments, etc.) | ||
* | ||
* The behavior of Update-with-Start in the case where there is already a running Workflow with | ||
* the given Workflow ID depends on the specified {@link WorkflowIDConflictPolicy}. That is, if | ||
* the policy is `USE_EXISTING`, then the Update is issued against the already existing Workflow | ||
* Execution; however, if the policy is `FAIL`, then an error is thrown. Caller MUST specify | ||
* the desired WorkflowIDConflictPolicy. | ||
* | ||
* This call will block until the Update has completed. The Workflow handle can be retrieved by | ||
* awaiting on {@link WithStartWorkflowOperation.workflowHandle}, whether or not the Update | ||
* succeeds. | ||
* | ||
* @returns the Update result | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
async executeUpdateWithStart(updateDef, updateOptions) { | ||
const handle = await this._startUpdateWithStart(updateDef, { | ||
...updateOptions, | ||
waitForStage: workflow_update_stage_1.WorkflowUpdateStage.COMPLETED, | ||
}); | ||
return await handle.result(); | ||
} | ||
/** | ||
* Start a new Workflow Execution and immediately send an Update to that Workflow, | ||
* then return a {@link WorkflowUpdateHandle} for that Update. | ||
* | ||
* The `updateOptions` object must contain a {@link WithStartWorkflowOperation}, which defines | ||
* the options for the Workflow execution to start (e.g. the Workflow's type, task queue, input | ||
* arguments, etc.) | ||
* | ||
* The behavior of Update-with-Start in the case where there is already a running Workflow with | ||
* the given Workflow ID depends on the specified {@link WorkflowIDConflictPolicy}. That is, if | ||
* the policy is `USE_EXISTING`, then the Update is issued against the already existing Workflow | ||
* Execution; however, if the policy is `FAIL`, then an error is thrown. Caller MUST specify | ||
* the desired WorkflowIDConflictPolicy. | ||
* | ||
* This call will block until the Update has reached the specified {@link WorkflowUpdateStage}. | ||
* Note that this means that the call will not return successfully until the Update has | ||
* been delivered to a Worker. The Workflow handle can be retrieved by awaiting on | ||
* {@link WithStartWorkflowOperation.workflowHandle}, whether or not the Update succeeds. | ||
* | ||
* @returns a {@link WorkflowUpdateHandle} to the started Update | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
async startUpdateWithStart(updateDef, updateOptions) { | ||
return this._startUpdateWithStart(updateDef, updateOptions); | ||
} | ||
async _startUpdateWithStart(updateDef, updateWithStartOptions) { | ||
const { waitForStage, args, startWorkflowOperation, ...updateOptions } = updateWithStartOptions; | ||
const { workflowTypeOrFunc, options: workflowOptions } = startWorkflowOperation; | ||
const { workflowId } = workflowOptions; | ||
if (startWorkflowOperation[withStartWorkflowOperationUsed]) { | ||
throw new Error('This WithStartWorkflowOperation instance has already been executed.'); | ||
} | ||
startWorkflowOperation[withStartWorkflowOperationUsed] = true; | ||
assertRequiredWorkflowOptions(workflowOptions); | ||
const startUpdateWithStartInput = { | ||
workflowType: (0, common_1.extractWorkflowType)(workflowTypeOrFunc), | ||
workflowStartOptions: (0, workflow_options_1.compileWorkflowOptions)(ensureArgs(workflowOptions)), | ||
workflowStartHeaders: {}, | ||
updateName: typeof updateDef === 'string' ? updateDef : updateDef.name, | ||
updateArgs: args ?? [], | ||
updateOptions, | ||
updateHeaders: {}, | ||
}; | ||
const interceptors = this.getOrMakeInterceptors(workflowId); | ||
const onStart = (startResponse) => startWorkflowOperation[withStartWorkflowOperationResolve](this._createWorkflowHandle({ | ||
workflowId, | ||
firstExecutionRunId: startResponse.runId ?? undefined, | ||
interceptors, | ||
followRuns: workflowOptions.followRuns ?? true, | ||
})); | ||
const onStartError = (err) => { | ||
startWorkflowOperation[withStartWorkflowOperationReject](err); | ||
}; | ||
const fn = (0, interceptors_1.composeInterceptors)(interceptors, 'startUpdateWithStart', this._updateWithStartHandler.bind(this, waitForStage, onStart, onStartError)); | ||
const updateOutput = await fn(startUpdateWithStartInput); | ||
let outcome = updateOutput.updateOutcome; | ||
if (!outcome && waitForStage === workflow_update_stage_1.WorkflowUpdateStage.COMPLETED) { | ||
outcome = await this._pollForUpdateOutcome(updateOutput.updateId, { | ||
workflowId, | ||
runId: updateOutput.workflowExecution.runId, | ||
}); | ||
} | ||
return this.createWorkflowUpdateHandle(updateOutput.updateId, workflowId, updateOutput.workflowExecution.runId, outcome); | ||
} | ||
/** | ||
* Start a new Workflow execution, then await for its completion and return that Workflow's result. | ||
* | ||
* @returns the result of the Workflow execution | ||
@@ -171,5 +287,5 @@ */ | ||
/** | ||
* Gets the result of a Workflow execution. | ||
* Get the result of a Workflow execution. | ||
* | ||
* Follows the chain of execution in case Workflow continues as new, or has a cron schedule or retry policy. | ||
* Follow the chain of execution in case Workflow continues as new, or has a cron schedule or retry policy. | ||
*/ | ||
@@ -284,3 +400,3 @@ async result(workflowId, runId, opts) { | ||
/** | ||
* Uses given input to make a queryWorkflow call to the service | ||
* Use given input to make a queryWorkflow call to the service | ||
* | ||
@@ -325,16 +441,5 @@ * Used as the final function of the query interceptor chain | ||
} | ||
/** | ||
* Start the Update. | ||
* | ||
* Used as the final function of the interceptor chain during startUpdate and executeUpdate. | ||
*/ | ||
async _startUpdateHandler(waitForStage, input) { | ||
let waitForStageProto = (0, workflow_update_stage_1.encodeWorkflowUpdateStage)(waitForStage) ?? | ||
UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED; | ||
waitForStageProto = | ||
waitForStageProto >= UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED | ||
? waitForStageProto | ||
: UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED; | ||
async _createUpdateWorkflowRequest(lifecycleStage, input) { | ||
const updateId = input.options?.updateId ?? (0, uuid_1.v4)(); | ||
const req = { | ||
return { | ||
namespace: this.options.namespace, | ||
@@ -344,3 +449,3 @@ workflowExecution: input.workflowExecution, | ||
waitPolicy: { | ||
lifecycleStage: waitForStageProto, | ||
lifecycleStage, | ||
}, | ||
@@ -359,10 +464,24 @@ request: { | ||
}; | ||
// Repeatedly send UpdateWorkflowExecution until update is >= Accepted or >= `waitForStage` (if | ||
// the server receives a request with an update ID that already exists, it responds with | ||
// information for the existing update). | ||
} | ||
/** | ||
* Start the Update. | ||
* | ||
* Used as the final function of the interceptor chain during startUpdate and executeUpdate. | ||
*/ | ||
async _startUpdateHandler(waitForStage, input) { | ||
let waitForStageProto = (0, workflow_update_stage_1.encodeWorkflowUpdateStage)(waitForStage) ?? | ||
UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED; | ||
waitForStageProto = | ||
waitForStageProto >= UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED | ||
? waitForStageProto | ||
: UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED; | ||
const request = await this._createUpdateWorkflowRequest(waitForStageProto, input); | ||
// Repeatedly send UpdateWorkflowExecution until update is durable (if the server receives a request with | ||
// an update ID that already exists, it responds with information for the existing update). If the | ||
// requested wait stage is COMPLETED, further polling is done before returning the UpdateHandle. | ||
let response; | ||
try { | ||
do { | ||
response = await this.workflowService.updateWorkflowExecution(req); | ||
} while (response.stage < waitForStageProto); | ||
response = await this.workflowService.updateWorkflowExecution(request); | ||
} while (response.stage < UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED); | ||
} | ||
@@ -373,3 +492,3 @@ catch (err) { | ||
return { | ||
updateId, | ||
updateId: request.request.meta.updateId, | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
@@ -380,2 +499,83 @@ workflowRunId: response.updateRef.workflowExecution.runId, | ||
} | ||
/** | ||
* Send the Update-With-Start MultiOperation request. | ||
* | ||
* Used as the final function of the interceptor chain during | ||
* startUpdateWithStart and executeUpdateWithStart. | ||
*/ | ||
async _updateWithStartHandler(waitForStage, onStart, onStartError, input) { | ||
const startInput = { | ||
workflowType: input.workflowType, | ||
options: input.workflowStartOptions, | ||
headers: input.workflowStartHeaders, | ||
}; | ||
const updateInput = { | ||
updateName: input.updateName, | ||
args: input.updateArgs, | ||
workflowExecution: { | ||
workflowId: input.workflowStartOptions.workflowId, | ||
}, | ||
options: input.updateOptions, | ||
headers: input.updateHeaders, | ||
}; | ||
let seenStart = false; | ||
try { | ||
const startRequest = await this.createStartWorkflowRequest(startInput); | ||
const waitForStageProto = (0, workflow_update_stage_1.encodeWorkflowUpdateStage)(waitForStage); | ||
const updateRequest = await this._createUpdateWorkflowRequest(waitForStageProto, updateInput); | ||
const multiOpReq = { | ||
namespace: this.options.namespace, | ||
operations: [ | ||
{ | ||
startWorkflow: startRequest, | ||
}, | ||
{ | ||
updateWorkflow: updateRequest, | ||
}, | ||
], | ||
}; | ||
let multiOpResp; | ||
let startResp; | ||
let updateResp; | ||
let reachedStage; | ||
// Repeatedly send ExecuteMultiOperation until update is durable (if the server receives a request with | ||
// an update ID that already exists, it responds with information for the existing update). If the | ||
// requested wait stage is COMPLETED, further polling is done before returning the UpdateHandle. | ||
do { | ||
multiOpResp = await this.workflowService.executeMultiOperation(multiOpReq); | ||
startResp = multiOpResp.responses?.[0] | ||
?.startWorkflow; | ||
if (!seenStart) { | ||
onStart(startResp); | ||
seenStart = true; | ||
} | ||
updateResp = multiOpResp.responses?.[1] | ||
?.updateWorkflow; | ||
reachedStage = | ||
updateResp.stage ?? | ||
UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_UNSPECIFIED; | ||
} while (reachedStage < UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED); | ||
return { | ||
workflowExecution: { | ||
workflowId: updateResp.updateRef.workflowExecution.workflowId, | ||
runId: updateResp.updateRef.workflowExecution.runId, | ||
}, | ||
updateId: updateRequest.request.meta.updateId, | ||
updateOutcome: updateResp.outcome ?? undefined, | ||
}; | ||
} | ||
catch (thrownError) { | ||
let err = thrownError; | ||
if ((0, errors_1.isGrpcServiceError)(err) && err.code === grpc_js_1.status.ALREADY_EXISTS) { | ||
err = new common_1.WorkflowExecutionAlreadyStartedError('Workflow execution already started', input.workflowStartOptions.workflowId, input.workflowType); | ||
} | ||
if (!seenStart) { | ||
onStartError(err); | ||
} | ||
if ((0, errors_1.isGrpcServiceError)(err)) { | ||
this.rethrowUpdateGrpcError(err, 'Update-With-Start failed', updateInput.workflowExecution); | ||
} | ||
throw err; | ||
} | ||
} | ||
createWorkflowUpdateHandle(updateId, workflowId, workflowRunId, outcome) { | ||
@@ -424,3 +624,3 @@ return { | ||
/** | ||
* Uses given input to make a signalWorkflowExecution call to the service | ||
* Use given input to make a signalWorkflowExecution call to the service | ||
* | ||
@@ -448,3 +648,3 @@ * Used as the final function of the signal interceptor chain | ||
/** | ||
* Uses given input to make a signalWithStartWorkflowExecution call to the service | ||
* Use given input to make a signalWithStartWorkflowExecution call to the service | ||
* | ||
@@ -496,3 +696,3 @@ * Used as the final function of the signalWithStart interceptor chain | ||
/** | ||
* Uses given input to make startWorkflowExecution call to the service | ||
* Use given input to make startWorkflowExecution call to the service | ||
* | ||
@@ -502,6 +702,19 @@ * Used as the final function of the start interceptor chain | ||
async _startWorkflowHandler(input) { | ||
const req = await this.createStartWorkflowRequest(input); | ||
const { options: opts, workflowType } = input; | ||
try { | ||
return (await this.workflowService.startWorkflowExecution(req)).runId; | ||
} | ||
catch (err) { | ||
if (err.code === grpc_js_1.status.ALREADY_EXISTS) { | ||
throw new common_1.WorkflowExecutionAlreadyStartedError('Workflow execution already started', opts.workflowId, workflowType); | ||
} | ||
this.rethrowGrpcError(err, 'Failed to start Workflow', { workflowId: opts.workflowId }); | ||
} | ||
} | ||
async createStartWorkflowRequest(input) { | ||
const { options: opts, workflowType, headers } = input; | ||
const { identity } = this.options; | ||
const req = { | ||
namespace: this.options.namespace, | ||
const { identity, namespace } = this.options; | ||
return { | ||
namespace, | ||
identity, | ||
@@ -532,14 +745,5 @@ requestId: (0, uuid_1.v4)(), | ||
}; | ||
try { | ||
return (await this.workflowService.startWorkflowExecution(req)).runId; | ||
} | ||
catch (err) { | ||
if (err.code === grpc_js_1.status.ALREADY_EXISTS) { | ||
throw new common_1.WorkflowExecutionAlreadyStartedError('Workflow execution already started', opts.workflowId, workflowType); | ||
} | ||
this.rethrowGrpcError(err, 'Failed to start Workflow', { workflowId: opts.workflowId }); | ||
} | ||
} | ||
/** | ||
* Uses given input to make terminateWorkflowExecution call to the service | ||
* Use given input to make terminateWorkflowExecution call to the service | ||
* | ||
@@ -764,5 +968,5 @@ * Used as the final function of the terminate interceptor chain | ||
/** | ||
* List workflows by given `query`. | ||
* Return a list of Workflow Executions matching the given `query`. | ||
* | ||
* ⚠️ To use advanced query functionality, as of the 1.18 server release, you must use Elasticsearch based visibility. | ||
* Note that the list of Workflow Executions returned is approximate and eventually consistent. | ||
* | ||
@@ -783,2 +987,24 @@ * More info on the concept of "visibility" and the query syntax on the Temporal documentation site: | ||
} | ||
/** | ||
* Return the number of Workflow Executions matching the given `query`. If no `query` is provided, then return the | ||
* total number of Workflow Executions for this namespace. | ||
* | ||
* Note that the number of Workflow Executions returned is approximate and eventually consistent. | ||
* | ||
* More info on the concept of "visibility" and the query syntax on the Temporal documentation site: | ||
* https://docs.temporal.io/visibility | ||
*/ | ||
async count(query) { | ||
let response; | ||
try { | ||
response = await this.workflowService.countWorkflowExecutions({ | ||
namespace: this.options.namespace, | ||
query, | ||
}); | ||
} | ||
catch (e) { | ||
this.rethrowGrpcError(e, 'Failed to count workflows'); | ||
} | ||
return (0, helpers_1.decodeCountWorkflowExecutionsResponse)(response); | ||
} | ||
getOrMakeInterceptors(workflowId, runId) { | ||
@@ -785,0 +1011,0 @@ if (typeof this.options.interceptors === 'object' && 'calls' in this.options.interceptors) { |
{ | ||
"name": "@temporalio/client", | ||
"version": "1.11.5", | ||
"version": "1.11.6", | ||
"description": "Temporal.io SDK Client sub-package", | ||
@@ -17,4 +17,4 @@ "main": "lib/index.js", | ||
"@grpc/grpc-js": "^1.10.7", | ||
"@temporalio/common": "1.11.5", | ||
"@temporalio/proto": "1.11.5", | ||
"@temporalio/common": "1.11.6", | ||
"@temporalio/proto": "1.11.6", | ||
"abort-controller": "^3.0.0", | ||
@@ -43,3 +43,3 @@ "long": "^5.2.3", | ||
], | ||
"gitHead": "a7b946cd5d4d58432509ead0f8d0c0c40742c107" | ||
"gitHead": "7b0543ade19c5432fd6013877489df28f96d9be0" | ||
} |
@@ -58,4 +58,4 @@ import os from 'node:os'; | ||
* | ||
* Clients are cheap to create, but connections are expensive. Where that make sense, | ||
* a single connection may and should be reused by multiple `Client`. | ||
* Clients are cheap to create, but connections are expensive. Where it makes sense, | ||
* a single connection may and should be reused by multiple `Client`s. | ||
*/ | ||
@@ -62,0 +62,0 @@ public readonly connection: ConnectionLike; |
@@ -1,2 +0,2 @@ | ||
import { ServiceError as GrpcServiceError } from '@grpc/grpc-js'; | ||
import { ServiceError as GrpcServiceError, status as grpcStatus } from '@grpc/grpc-js'; | ||
import { | ||
@@ -13,3 +13,8 @@ LoadedDataConverter, | ||
import { temporal, google } from '@temporalio/proto'; | ||
import { RawWorkflowExecutionInfo, WorkflowExecutionInfo, WorkflowExecutionStatusName } from './types'; | ||
import { | ||
CountWorkflowExecution, | ||
RawWorkflowExecutionInfo, | ||
WorkflowExecutionInfo, | ||
WorkflowExecutionStatusName, | ||
} from './types'; | ||
@@ -85,3 +90,20 @@ function workflowStatusCodeToName(code: temporal.api.enums.v1.WorkflowExecutionStatus): WorkflowExecutionStatusName { | ||
export function decodeCountWorkflowExecutionsResponse( | ||
raw: temporal.api.workflowservice.v1.ICountWorkflowExecutionsResponse | ||
): CountWorkflowExecution { | ||
return { | ||
// Note: lossy conversion of Long to number | ||
count: raw.count!.toNumber(), | ||
groups: raw.groups!.map((group) => { | ||
return { | ||
// Note: lossy conversion of Long to number | ||
count: group.count!.toNumber(), | ||
groupValues: group.groupValues!.map((value) => searchAttributePayloadConverter.fromPayload(value)), | ||
}; | ||
}), | ||
}; | ||
} | ||
type ErrorDetailsName = `temporal.api.errordetails.v1.${keyof typeof temporal.api.errordetails.v1}`; | ||
type FailureName = `temporal.api.failure.v1.${keyof typeof temporal.api.failure.v1}`; | ||
@@ -107,2 +129,24 @@ /** | ||
} | ||
case 'temporal.api.errordetails.v1.MultiOperationExecutionFailure': { | ||
// MultiOperationExecutionFailure contains error statuses for multiple | ||
// operations. A MultiOperationExecutionAborted error status means that | ||
// the corresponding operation was aborted due to an error in one of the | ||
// other operations. We rethrow the first operation error that is not | ||
// MultiOperationExecutionAborted. | ||
const { statuses } = temporal.api.errordetails.v1.MultiOperationExecutionFailure.decode(entry.value); | ||
for (const status of statuses) { | ||
const detail = status.details?.[0]; | ||
const statusType = detail?.type_url?.replace(/^type.googleapis.com\//, '') as FailureName | undefined; | ||
if ( | ||
statusType === 'temporal.api.failure.v1.MultiOperationExecutionAborted' || | ||
status.code === grpcStatus.OK | ||
) { | ||
continue; | ||
} | ||
err.message = status.message ?? err.message; | ||
err.code = status.code || err.code; | ||
err.details = detail?.value?.toString() || err.details; | ||
throw err; | ||
} | ||
} | ||
} | ||
@@ -109,0 +153,0 @@ } |
@@ -45,2 +45,28 @@ /** | ||
/** | ||
* Input for WorkflowClientInterceptor.startUpdateWithStart | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
export interface WorkflowStartUpdateWithStartInput { | ||
readonly workflowType: string; | ||
readonly workflowStartOptions: CompiledWorkflowOptions; | ||
readonly workflowStartHeaders: Headers; | ||
readonly updateName: string; | ||
readonly updateArgs: unknown[]; | ||
readonly updateOptions: WorkflowUpdateOptions; | ||
readonly updateHeaders: Headers; | ||
} | ||
/** | ||
* Output for WorkflowClientInterceptor.startUpdateWithStart | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
export interface WorkflowStartUpdateWithStartOutput { | ||
readonly workflowExecution: WorkflowExecution; | ||
readonly updateId: string; | ||
readonly updateOutcome?: temporal.api.update.v1.IOutcome; | ||
} | ||
/** Input for WorkflowClientInterceptor.signal */ | ||
@@ -104,4 +130,2 @@ export interface WorkflowSignalInput { | ||
* Intercept a service call to updateWorkflowExecution | ||
* | ||
* @experimental Update is an experimental feature. | ||
*/ | ||
@@ -113,2 +137,11 @@ startUpdate?: ( | ||
/** | ||
* Intercept a service call to startUpdateWithStart | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
startUpdateWithStart?: ( | ||
input: WorkflowStartUpdateWithStartInput, | ||
next: Next<this, 'startUpdateWithStart'> | ||
) => Promise<WorkflowStartUpdateWithStartOutput>; | ||
/** | ||
* Intercept a service call to signalWorkflowExecution | ||
@@ -115,0 +148,0 @@ * |
import type * as grpc from '@grpc/grpc-js'; | ||
import type { SearchAttributes } from '@temporalio/common'; | ||
import type { SearchAttributes, SearchAttributeValue } from '@temporalio/common'; | ||
import { makeProtoEnumConverters } from '@temporalio/common/lib/internal-workflow'; | ||
@@ -55,2 +55,10 @@ import * as proto from '@temporalio/proto'; | ||
export interface CountWorkflowExecution { | ||
count: number; | ||
groups: { | ||
count: number; | ||
groupValues: SearchAttributeValue[]; | ||
}[]; | ||
} | ||
export type WorkflowExecutionDescription = Replace< | ||
@@ -57,0 +65,0 @@ WorkflowExecutionInfo, |
@@ -26,2 +26,3 @@ import { status as grpcStatus } from '@grpc/grpc-js'; | ||
encodeWorkflowIdConflictPolicy, | ||
WorkflowIdConflictPolicy, | ||
} from '@temporalio/common'; | ||
@@ -60,4 +61,7 @@ import { composeInterceptors } from '@temporalio/common/lib/interceptors'; | ||
WorkflowStartUpdateOutput, | ||
WorkflowStartUpdateWithStartInput, | ||
WorkflowStartUpdateWithStartOutput, | ||
} from './interceptors'; | ||
import { | ||
CountWorkflowExecution, | ||
DescribeWorkflowExecutionResponse, | ||
@@ -82,3 +86,3 @@ encodeQueryRejectCondition, | ||
} from './workflow-options'; | ||
import { executionInfoFromRaw, rethrowKnownErrorTypes } from './helpers'; | ||
import { decodeCountWorkflowExecutionsResponse, executionInfoFromRaw, rethrowKnownErrorTypes } from './helpers'; | ||
import { | ||
@@ -130,4 +134,2 @@ BaseClient, | ||
* | ||
* @experimental Update is an experimental feature. | ||
* | ||
* @throws {@link WorkflowUpdateFailedError} if Update validation fails or if ApplicationFailure is thrown in the Update handler. | ||
@@ -158,4 +160,2 @@ * @throws {@link WorkflowUpdateRPCTimeoutOrCancelledError} if this Update call timed out or was cancelled. This doesn't | ||
* | ||
* @experimental Update is an experimental feature. | ||
* | ||
* @throws {@link WorkflowUpdateFailedError} if Update validation fails. | ||
@@ -309,3 +309,3 @@ * @throws {@link WorkflowUpdateRPCTimeoutOrCancelledError} if this Update call timed out or was cancelled. This doesn't | ||
function assertRequiredWorkflowOptions(opts: WorkflowOptions): void { | ||
function assertRequiredWorkflowOptions(opts: WorkflowOptions): asserts opts is WorkflowOptions { | ||
if (!opts.taskQueue) { | ||
@@ -459,3 +459,34 @@ throw new TypeError('Missing WorkflowOptions.taskQueue'); | ||
const withStartWorkflowOperationResolve: unique symbol = Symbol(); | ||
const withStartWorkflowOperationReject: unique symbol = Symbol(); | ||
const withStartWorkflowOperationUsed: unique symbol = Symbol(); | ||
/** | ||
* Define how to start a workflow when using {@link WorkflowClient.startUpdateWithStart} and | ||
* {@link WorkflowClient.executeUpdateWithStart}. `workflowIdConflictPolicy` is required in the options. | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
export class WithStartWorkflowOperation<T extends Workflow> { | ||
private [withStartWorkflowOperationUsed]: boolean = false; | ||
private [withStartWorkflowOperationResolve]: ((handle: WorkflowHandle<T>) => void) | undefined = undefined; | ||
private [withStartWorkflowOperationReject]: ((error: any) => void) | undefined = undefined; | ||
private workflowHandlePromise: Promise<WorkflowHandle<T>>; | ||
constructor( | ||
public workflowTypeOrFunc: string | T, | ||
public options: WorkflowStartOptions<T> & { workflowIdConflictPolicy: WorkflowIdConflictPolicy } | ||
) { | ||
this.workflowHandlePromise = new Promise<WorkflowHandle<T>>((resolve, reject) => { | ||
this[withStartWorkflowOperationResolve] = resolve; | ||
this[withStartWorkflowOperationReject] = reject; | ||
}); | ||
} | ||
public async workflowHandle(): Promise<WorkflowHandle<T>> { | ||
return await this.workflowHandlePromise; | ||
} | ||
} | ||
/** | ||
* Client for starting Workflow executions and creating Workflow handles. | ||
@@ -488,7 +519,2 @@ * | ||
/** | ||
* Start a new Workflow execution. | ||
* | ||
* @returns the execution's `runId`. | ||
*/ | ||
protected async _start<T extends Workflow>( | ||
@@ -512,8 +538,2 @@ workflowTypeOrFunc: string | T, | ||
/** | ||
* Sends a signal to a running Workflow or starts a new one if not already running and immediately signals it. | ||
* Useful when you're unsure of the Workflow's run state. | ||
* | ||
* @returns the runId of the Workflow | ||
*/ | ||
protected async _signalWithStart<T extends Workflow, SA extends any[]>( | ||
@@ -547,3 +567,3 @@ workflowTypeOrFunc: string | T, | ||
* | ||
* @returns a WorkflowHandle to the started Workflow | ||
* @returns a {@link WorkflowHandle} to the started Workflow | ||
*/ | ||
@@ -572,5 +592,10 @@ public async start<T extends Workflow>( | ||
/** | ||
* Sends a Signal to a running Workflow or starts a new one if not already running and immediately Signals it. | ||
* Useful when you're unsure whether the Workflow has been started. | ||
* Start a new Workflow Execution and immediately send a Signal to that Workflow. | ||
* | ||
* The behavior of Signal-with-Start in the case where there is already a running Workflow with | ||
* the given Workflow ID depends on the {@link WorkflowIDConflictPolicy}. That is, if the policy | ||
* is `USE_EXISTING`, then the Signal is issued against the already existing Workflow Execution; | ||
* however, if the policy is `FAIL`, then an error is thrown. If no policy is specified, | ||
* Signal-with-Start defaults to `USE_EXISTING`. | ||
* | ||
* @returns a {@link WorkflowHandle} to the started Workflow | ||
@@ -600,4 +625,138 @@ */ | ||
/** | ||
* Starts a new Workflow execution and awaits its completion. | ||
* Start a new Workflow Execution and immediately send an Update to that Workflow, | ||
* then await and return the Update's result. | ||
* | ||
* The `updateOptions` object must contain a {@link WithStartWorkflowOperation}, which defines | ||
* the options for the Workflow execution to start (e.g. the Workflow's type, task queue, input | ||
* arguments, etc.) | ||
* | ||
* The behavior of Update-with-Start in the case where there is already a running Workflow with | ||
* the given Workflow ID depends on the specified {@link WorkflowIDConflictPolicy}. That is, if | ||
* the policy is `USE_EXISTING`, then the Update is issued against the already existing Workflow | ||
* Execution; however, if the policy is `FAIL`, then an error is thrown. Caller MUST specify | ||
* the desired WorkflowIDConflictPolicy. | ||
* | ||
* This call will block until the Update has completed. The Workflow handle can be retrieved by | ||
* awaiting on {@link WithStartWorkflowOperation.workflowHandle}, whether or not the Update | ||
* succeeds. | ||
* | ||
* @returns the Update result | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
public async executeUpdateWithStart<T extends Workflow, Ret, Args extends any[]>( | ||
updateDef: UpdateDefinition<Ret, Args> | string, | ||
updateOptions: WorkflowUpdateOptions & { args?: Args; startWorkflowOperation: WithStartWorkflowOperation<T> } | ||
): Promise<Ret> { | ||
const handle = await this._startUpdateWithStart(updateDef, { | ||
...updateOptions, | ||
waitForStage: WorkflowUpdateStage.COMPLETED, | ||
}); | ||
return await handle.result(); | ||
} | ||
/** | ||
* Start a new Workflow Execution and immediately send an Update to that Workflow, | ||
* then return a {@link WorkflowUpdateHandle} for that Update. | ||
* | ||
* The `updateOptions` object must contain a {@link WithStartWorkflowOperation}, which defines | ||
* the options for the Workflow execution to start (e.g. the Workflow's type, task queue, input | ||
* arguments, etc.) | ||
* | ||
* The behavior of Update-with-Start in the case where there is already a running Workflow with | ||
* the given Workflow ID depends on the specified {@link WorkflowIDConflictPolicy}. That is, if | ||
* the policy is `USE_EXISTING`, then the Update is issued against the already existing Workflow | ||
* Execution; however, if the policy is `FAIL`, then an error is thrown. Caller MUST specify | ||
* the desired WorkflowIDConflictPolicy. | ||
* | ||
* This call will block until the Update has reached the specified {@link WorkflowUpdateStage}. | ||
* Note that this means that the call will not return successfully until the Update has | ||
* been delivered to a Worker. The Workflow handle can be retrieved by awaiting on | ||
* {@link WithStartWorkflowOperation.workflowHandle}, whether or not the Update succeeds. | ||
* | ||
* @returns a {@link WorkflowUpdateHandle} to the started Update | ||
* | ||
* @experimental Update-with-Start is an experimental feature and may be subject to change. | ||
*/ | ||
public async startUpdateWithStart<T extends Workflow, Ret, Args extends any[]>( | ||
updateDef: UpdateDefinition<Ret, Args> | string, | ||
updateOptions: WorkflowUpdateOptions & { | ||
args?: Args; | ||
waitForStage: 'ACCEPTED'; | ||
startWorkflowOperation: WithStartWorkflowOperation<T>; | ||
} | ||
): Promise<WorkflowUpdateHandle<Ret>> { | ||
return this._startUpdateWithStart(updateDef, updateOptions); | ||
} | ||
protected async _startUpdateWithStart<T extends Workflow, Ret, Args extends any[]>( | ||
updateDef: UpdateDefinition<Ret, Args> | string, | ||
updateWithStartOptions: WorkflowUpdateOptions & { | ||
args?: Args; | ||
waitForStage: WorkflowUpdateStage; | ||
startWorkflowOperation: WithStartWorkflowOperation<T>; | ||
} | ||
): Promise<WorkflowUpdateHandle<Ret>> { | ||
const { waitForStage, args, startWorkflowOperation, ...updateOptions } = updateWithStartOptions; | ||
const { workflowTypeOrFunc, options: workflowOptions } = startWorkflowOperation; | ||
const { workflowId } = workflowOptions; | ||
if (startWorkflowOperation[withStartWorkflowOperationUsed]) { | ||
throw new Error('This WithStartWorkflowOperation instance has already been executed.'); | ||
} | ||
startWorkflowOperation[withStartWorkflowOperationUsed] = true; | ||
assertRequiredWorkflowOptions(workflowOptions); | ||
const startUpdateWithStartInput: WorkflowStartUpdateWithStartInput = { | ||
workflowType: extractWorkflowType(workflowTypeOrFunc), | ||
workflowStartOptions: compileWorkflowOptions(ensureArgs(workflowOptions)), | ||
workflowStartHeaders: {}, | ||
updateName: typeof updateDef === 'string' ? updateDef : updateDef.name, | ||
updateArgs: args ?? [], | ||
updateOptions, | ||
updateHeaders: {}, | ||
}; | ||
const interceptors = this.getOrMakeInterceptors(workflowId); | ||
const onStart = (startResponse: temporal.api.workflowservice.v1.IStartWorkflowExecutionResponse) => | ||
startWorkflowOperation[withStartWorkflowOperationResolve]!( | ||
this._createWorkflowHandle({ | ||
workflowId, | ||
firstExecutionRunId: startResponse.runId ?? undefined, | ||
interceptors, | ||
followRuns: workflowOptions.followRuns ?? true, | ||
}) | ||
); | ||
const onStartError = (err: any) => { | ||
startWorkflowOperation[withStartWorkflowOperationReject]!(err); | ||
}; | ||
const fn = composeInterceptors( | ||
interceptors, | ||
'startUpdateWithStart', | ||
this._updateWithStartHandler.bind(this, waitForStage, onStart, onStartError) | ||
); | ||
const updateOutput = await fn(startUpdateWithStartInput); | ||
let outcome = updateOutput.updateOutcome; | ||
if (!outcome && waitForStage === WorkflowUpdateStage.COMPLETED) { | ||
outcome = await this._pollForUpdateOutcome(updateOutput.updateId, { | ||
workflowId, | ||
runId: updateOutput.workflowExecution.runId, | ||
}); | ||
} | ||
return this.createWorkflowUpdateHandle<Ret>( | ||
updateOutput.updateId, | ||
workflowId, | ||
updateOutput.workflowExecution.runId, | ||
outcome | ||
); | ||
} | ||
/** | ||
* Start a new Workflow execution, then await for its completion and return that Workflow's result. | ||
* | ||
* @returns the result of the Workflow execution | ||
@@ -619,5 +778,5 @@ */ | ||
/** | ||
* Gets the result of a Workflow execution. | ||
* Get the result of a Workflow execution. | ||
* | ||
* Follows the chain of execution in case Workflow continues as new, or has a cron schedule or retry policy. | ||
* Follow the chain of execution in case Workflow continues as new, or has a cron schedule or retry policy. | ||
*/ | ||
@@ -771,3 +930,3 @@ public async result<T extends Workflow>( | ||
/** | ||
* Uses given input to make a queryWorkflow call to the service | ||
* Use given input to make a queryWorkflow call to the service | ||
* | ||
@@ -812,22 +971,8 @@ * Used as the final function of the query interceptor chain | ||
/** | ||
* Start the Update. | ||
* | ||
* Used as the final function of the interceptor chain during startUpdate and executeUpdate. | ||
*/ | ||
protected async _startUpdateHandler( | ||
waitForStage: WorkflowUpdateStage, | ||
protected async _createUpdateWorkflowRequest( | ||
lifecycleStage: temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage, | ||
input: WorkflowStartUpdateInput | ||
): Promise<WorkflowStartUpdateOutput> { | ||
let waitForStageProto: temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage = | ||
encodeWorkflowUpdateStage(waitForStage) ?? | ||
UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED; | ||
waitForStageProto = | ||
waitForStageProto >= UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED | ||
? waitForStageProto | ||
: UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED; | ||
): Promise<temporal.api.workflowservice.v1.IUpdateWorkflowExecutionRequest> { | ||
const updateId = input.options?.updateId ?? uuid4(); | ||
const req: temporal.api.workflowservice.v1.IUpdateWorkflowExecutionRequest = { | ||
return { | ||
namespace: this.options.namespace, | ||
@@ -837,3 +982,3 @@ workflowExecution: input.workflowExecution, | ||
waitPolicy: { | ||
lifecycleStage: waitForStageProto, | ||
lifecycleStage, | ||
}, | ||
@@ -852,11 +997,34 @@ request: { | ||
}; | ||
} | ||
// Repeatedly send UpdateWorkflowExecution until update is >= Accepted or >= `waitForStage` (if | ||
// the server receives a request with an update ID that already exists, it responds with | ||
// information for the existing update). | ||
/** | ||
* Start the Update. | ||
* | ||
* Used as the final function of the interceptor chain during startUpdate and executeUpdate. | ||
*/ | ||
protected async _startUpdateHandler( | ||
waitForStage: WorkflowUpdateStage, | ||
input: WorkflowStartUpdateInput | ||
): Promise<WorkflowStartUpdateOutput> { | ||
let waitForStageProto: temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage = | ||
encodeWorkflowUpdateStage(waitForStage) ?? | ||
UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED; | ||
waitForStageProto = | ||
waitForStageProto >= UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED | ||
? waitForStageProto | ||
: UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED; | ||
const request = await this._createUpdateWorkflowRequest(waitForStageProto, input); | ||
// Repeatedly send UpdateWorkflowExecution until update is durable (if the server receives a request with | ||
// an update ID that already exists, it responds with information for the existing update). If the | ||
// requested wait stage is COMPLETED, further polling is done before returning the UpdateHandle. | ||
let response: temporal.api.workflowservice.v1.UpdateWorkflowExecutionResponse; | ||
try { | ||
do { | ||
response = await this.workflowService.updateWorkflowExecution(req); | ||
} while (response.stage < waitForStageProto); | ||
response = await this.workflowService.updateWorkflowExecution(request); | ||
} while ( | ||
response.stage < UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED | ||
); | ||
} catch (err) { | ||
@@ -866,3 +1034,3 @@ this.rethrowUpdateGrpcError(err, 'Workflow Update failed', input.workflowExecution); | ||
return { | ||
updateId, | ||
updateId: request.request!.meta!.updateId!, | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
@@ -874,2 +1042,93 @@ workflowRunId: response.updateRef!.workflowExecution!.runId!, | ||
/** | ||
* Send the Update-With-Start MultiOperation request. | ||
* | ||
* Used as the final function of the interceptor chain during | ||
* startUpdateWithStart and executeUpdateWithStart. | ||
*/ | ||
protected async _updateWithStartHandler( | ||
waitForStage: WorkflowUpdateStage, | ||
onStart: (startResponse: temporal.api.workflowservice.v1.IStartWorkflowExecutionResponse) => void, | ||
onStartError: (err: any) => void, | ||
input: WorkflowStartUpdateWithStartInput | ||
): Promise<WorkflowStartUpdateWithStartOutput> { | ||
const startInput: WorkflowStartInput = { | ||
workflowType: input.workflowType, | ||
options: input.workflowStartOptions, | ||
headers: input.workflowStartHeaders, | ||
}; | ||
const updateInput: WorkflowStartUpdateInput = { | ||
updateName: input.updateName, | ||
args: input.updateArgs, | ||
workflowExecution: { | ||
workflowId: input.workflowStartOptions.workflowId, | ||
}, | ||
options: input.updateOptions, | ||
headers: input.updateHeaders, | ||
}; | ||
let seenStart = false; | ||
try { | ||
const startRequest = await this.createStartWorkflowRequest(startInput); | ||
const waitForStageProto = encodeWorkflowUpdateStage(waitForStage)!; | ||
const updateRequest = await this._createUpdateWorkflowRequest(waitForStageProto, updateInput); | ||
const multiOpReq: temporal.api.workflowservice.v1.IExecuteMultiOperationRequest = { | ||
namespace: this.options.namespace, | ||
operations: [ | ||
{ | ||
startWorkflow: startRequest, | ||
}, | ||
{ | ||
updateWorkflow: updateRequest, | ||
}, | ||
], | ||
}; | ||
let multiOpResp: temporal.api.workflowservice.v1.IExecuteMultiOperationResponse; | ||
let startResp: temporal.api.workflowservice.v1.IStartWorkflowExecutionResponse; | ||
let updateResp: temporal.api.workflowservice.v1.IUpdateWorkflowExecutionResponse; | ||
let reachedStage: temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage; | ||
// Repeatedly send ExecuteMultiOperation until update is durable (if the server receives a request with | ||
// an update ID that already exists, it responds with information for the existing update). If the | ||
// requested wait stage is COMPLETED, further polling is done before returning the UpdateHandle. | ||
do { | ||
multiOpResp = await this.workflowService.executeMultiOperation(multiOpReq); | ||
startResp = multiOpResp.responses?.[0] | ||
?.startWorkflow as temporal.api.workflowservice.v1.IStartWorkflowExecutionResponse; | ||
if (!seenStart) { | ||
onStart(startResp); | ||
seenStart = true; | ||
} | ||
updateResp = multiOpResp.responses?.[1] | ||
?.updateWorkflow as temporal.api.workflowservice.v1.IUpdateWorkflowExecutionResponse; | ||
reachedStage = | ||
updateResp.stage ?? | ||
UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_UNSPECIFIED; | ||
} while (reachedStage < UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED); | ||
return { | ||
workflowExecution: { | ||
workflowId: updateResp.updateRef!.workflowExecution!.workflowId!, | ||
runId: updateResp.updateRef!.workflowExecution!.runId!, | ||
}, | ||
updateId: updateRequest.request!.meta!.updateId!, | ||
updateOutcome: updateResp.outcome ?? undefined, | ||
}; | ||
} catch (thrownError) { | ||
let err = thrownError; | ||
if (isGrpcServiceError(err) && err.code === grpcStatus.ALREADY_EXISTS) { | ||
err = new WorkflowExecutionAlreadyStartedError( | ||
'Workflow execution already started', | ||
input.workflowStartOptions.workflowId, | ||
input.workflowType | ||
); | ||
} | ||
if (!seenStart) { | ||
onStartError(err); | ||
} | ||
if (isGrpcServiceError(err)) { | ||
this.rethrowUpdateGrpcError(err, 'Update-With-Start failed', updateInput.workflowExecution); | ||
} | ||
throw err; | ||
} | ||
} | ||
protected createWorkflowUpdateHandle<Ret>( | ||
@@ -930,3 +1189,3 @@ updateId: string, | ||
/** | ||
* Uses given input to make a signalWorkflowExecution call to the service | ||
* Use given input to make a signalWorkflowExecution call to the service | ||
* | ||
@@ -954,3 +1213,3 @@ * Used as the final function of the signal interceptor chain | ||
/** | ||
* Uses given input to make a signalWithStartWorkflowExecution call to the service | ||
* Use given input to make a signalWithStartWorkflowExecution call to the service | ||
* | ||
@@ -1006,3 +1265,3 @@ * Used as the final function of the signalWithStart interceptor chain | ||
/** | ||
* Uses given input to make startWorkflowExecution call to the service | ||
* Use given input to make startWorkflowExecution call to the service | ||
* | ||
@@ -1012,6 +1271,23 @@ * Used as the final function of the start interceptor chain | ||
protected async _startWorkflowHandler(input: WorkflowStartInput): Promise<string> { | ||
const req = await this.createStartWorkflowRequest(input); | ||
const { options: opts, workflowType } = input; | ||
try { | ||
return (await this.workflowService.startWorkflowExecution(req)).runId; | ||
} catch (err: any) { | ||
if (err.code === grpcStatus.ALREADY_EXISTS) { | ||
throw new WorkflowExecutionAlreadyStartedError( | ||
'Workflow execution already started', | ||
opts.workflowId, | ||
workflowType | ||
); | ||
} | ||
this.rethrowGrpcError(err, 'Failed to start Workflow', { workflowId: opts.workflowId }); | ||
} | ||
} | ||
protected async createStartWorkflowRequest(input: WorkflowStartInput): Promise<StartWorkflowExecutionRequest> { | ||
const { options: opts, workflowType, headers } = input; | ||
const { identity } = this.options; | ||
const req: StartWorkflowExecutionRequest = { | ||
namespace: this.options.namespace, | ||
const { identity, namespace } = this.options; | ||
return { | ||
namespace, | ||
identity, | ||
@@ -1042,18 +1318,6 @@ requestId: uuid4(), | ||
}; | ||
try { | ||
return (await this.workflowService.startWorkflowExecution(req)).runId; | ||
} catch (err: any) { | ||
if (err.code === grpcStatus.ALREADY_EXISTS) { | ||
throw new WorkflowExecutionAlreadyStartedError( | ||
'Workflow execution already started', | ||
opts.workflowId, | ||
workflowType | ||
); | ||
} | ||
this.rethrowGrpcError(err, 'Failed to start Workflow', { workflowId: opts.workflowId }); | ||
} | ||
} | ||
/** | ||
* Uses given input to make terminateWorkflowExecution call to the service | ||
* Use given input to make terminateWorkflowExecution call to the service | ||
* | ||
@@ -1312,5 +1576,5 @@ * Used as the final function of the terminate interceptor chain | ||
/** | ||
* List workflows by given `query`. | ||
* Return a list of Workflow Executions matching the given `query`. | ||
* | ||
* ⚠️ To use advanced query functionality, as of the 1.18 server release, you must use Elasticsearch based visibility. | ||
* Note that the list of Workflow Executions returned is approximate and eventually consistent. | ||
* | ||
@@ -1336,2 +1600,25 @@ * More info on the concept of "visibility" and the query syntax on the Temporal documentation site: | ||
/** | ||
* Return the number of Workflow Executions matching the given `query`. If no `query` is provided, then return the | ||
* total number of Workflow Executions for this namespace. | ||
* | ||
* Note that the number of Workflow Executions returned is approximate and eventually consistent. | ||
* | ||
* More info on the concept of "visibility" and the query syntax on the Temporal documentation site: | ||
* https://docs.temporal.io/visibility | ||
*/ | ||
public async count(query?: string): Promise<CountWorkflowExecution> { | ||
let response: temporal.api.workflowservice.v1.CountWorkflowExecutionsResponse; | ||
try { | ||
response = await this.workflowService.countWorkflowExecutions({ | ||
namespace: this.options.namespace, | ||
query, | ||
}); | ||
} catch (e) { | ||
this.rethrowGrpcError(e, 'Failed to count workflows'); | ||
} | ||
return decodeCountWorkflowExecutionsResponse(response); | ||
} | ||
protected getOrMakeInterceptors(workflowId: string, runId?: string): WorkflowClientInterceptor[] { | ||
@@ -1338,0 +1625,0 @@ if (typeof this.options.interceptors === 'object' && 'calls' in this.options.interceptors) { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
589790
11972
+ Added@temporalio/common@1.11.6(transitive)
+ Added@temporalio/proto@1.11.6(transitive)
- Removed@temporalio/common@1.11.5(transitive)
- Removed@temporalio/proto@1.11.5(transitive)
Updated@temporalio/common@1.11.6
Updated@temporalio/proto@1.11.6