@temporalio/client 1.11.4 → 1.11.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/base-client.d.ts +2 -2
- package/lib/helpers.d.ts +3 -1
- package/lib/helpers.js +35 -0
- package/lib/helpers.js.map +1 -1
- package/lib/interceptors.d.ts +30 -2
- package/lib/types.d.ts +8 -1
- package/lib/types.js.map +1 -1
- package/lib/workflow-client.d.ts +121 -30
- package/lib/workflow-client.js +283 -57
- package/lib/workflow-client.js.map +1 -1
- package/package.json +4 -4
- package/src/base-client.ts +2 -2
- package/src/helpers.ts +46 -2
- package/src/interceptors.ts +35 -2
- package/src/types.ts +9 -1
- package/src/workflow-client.ts +357 -70
package/src/workflow-client.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
encodeWorkflowIdReusePolicy,
|
|
24
24
|
decodeRetryState,
|
|
25
25
|
encodeWorkflowIdConflictPolicy,
|
|
26
|
+
WorkflowIdConflictPolicy,
|
|
26
27
|
} from '@temporalio/common';
|
|
27
28
|
import { composeInterceptors } from '@temporalio/common/lib/interceptors';
|
|
28
29
|
import { History } from '@temporalio/common/lib/proto-utils';
|
|
@@ -56,8 +57,11 @@ import {
|
|
|
56
57
|
WorkflowTerminateInput,
|
|
57
58
|
WorkflowStartUpdateInput,
|
|
58
59
|
WorkflowStartUpdateOutput,
|
|
60
|
+
WorkflowStartUpdateWithStartInput,
|
|
61
|
+
WorkflowStartUpdateWithStartOutput,
|
|
59
62
|
} from './interceptors';
|
|
60
63
|
import {
|
|
64
|
+
CountWorkflowExecution,
|
|
61
65
|
DescribeWorkflowExecutionResponse,
|
|
62
66
|
encodeQueryRejectCondition,
|
|
63
67
|
GetWorkflowExecutionHistoryRequest,
|
|
@@ -77,7 +81,7 @@ import {
|
|
|
77
81
|
WorkflowStartOptions,
|
|
78
82
|
WorkflowUpdateOptions,
|
|
79
83
|
} from './workflow-options';
|
|
80
|
-
import { executionInfoFromRaw, rethrowKnownErrorTypes } from './helpers';
|
|
84
|
+
import { decodeCountWorkflowExecutionsResponse, executionInfoFromRaw, rethrowKnownErrorTypes } from './helpers';
|
|
81
85
|
import {
|
|
82
86
|
BaseClient,
|
|
83
87
|
BaseClientOptions,
|
|
@@ -124,8 +128,6 @@ export interface WorkflowHandle<T extends Workflow = Workflow> extends BaseWorkf
|
|
|
124
128
|
/**
|
|
125
129
|
* Start an Update and wait for the result.
|
|
126
130
|
*
|
|
127
|
-
* @experimental Update is an experimental feature.
|
|
128
|
-
*
|
|
129
131
|
* @throws {@link WorkflowUpdateFailedError} if Update validation fails or if ApplicationFailure is thrown in the Update handler.
|
|
130
132
|
* @throws {@link WorkflowUpdateRPCTimeoutOrCancelledError} if this Update call timed out or was cancelled. This doesn't
|
|
131
133
|
* mean the update itself was timed out or cancelled.
|
|
@@ -151,8 +153,6 @@ export interface WorkflowHandle<T extends Workflow = Workflow> extends BaseWorkf
|
|
|
151
153
|
* Start an Update and receive a handle to the Update. The Update validator (if present) is run
|
|
152
154
|
* before the handle is returned.
|
|
153
155
|
*
|
|
154
|
-
* @experimental Update is an experimental feature.
|
|
155
|
-
*
|
|
156
156
|
* @throws {@link WorkflowUpdateFailedError} if Update validation fails.
|
|
157
157
|
* @throws {@link WorkflowUpdateRPCTimeoutOrCancelledError} if this Update call timed out or was cancelled. This doesn't
|
|
158
158
|
* mean the update itself was timed out or cancelled.
|
|
@@ -301,7 +301,7 @@ function defaultWorkflowClientOptions(): WithDefaults<WorkflowClientOptions> {
|
|
|
301
301
|
};
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
-
function assertRequiredWorkflowOptions(opts: WorkflowOptions):
|
|
304
|
+
function assertRequiredWorkflowOptions(opts: WorkflowOptions): asserts opts is WorkflowOptions {
|
|
305
305
|
if (!opts.taskQueue) {
|
|
306
306
|
throw new TypeError('Missing WorkflowOptions.taskQueue');
|
|
307
307
|
}
|
|
@@ -450,6 +450,37 @@ export interface IntoHistoriesOptions {
|
|
|
450
450
|
bufferLimit?: number;
|
|
451
451
|
}
|
|
452
452
|
|
|
453
|
+
const withStartWorkflowOperationResolve: unique symbol = Symbol();
|
|
454
|
+
const withStartWorkflowOperationReject: unique symbol = Symbol();
|
|
455
|
+
const withStartWorkflowOperationUsed: unique symbol = Symbol();
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Define how to start a workflow when using {@link WorkflowClient.startUpdateWithStart} and
|
|
459
|
+
* {@link WorkflowClient.executeUpdateWithStart}. `workflowIdConflictPolicy` is required in the options.
|
|
460
|
+
*
|
|
461
|
+
* @experimental Update-with-Start is an experimental feature and may be subject to change.
|
|
462
|
+
*/
|
|
463
|
+
export class WithStartWorkflowOperation<T extends Workflow> {
|
|
464
|
+
private [withStartWorkflowOperationUsed]: boolean = false;
|
|
465
|
+
private [withStartWorkflowOperationResolve]: ((handle: WorkflowHandle<T>) => void) | undefined = undefined;
|
|
466
|
+
private [withStartWorkflowOperationReject]: ((error: any) => void) | undefined = undefined;
|
|
467
|
+
private workflowHandlePromise: Promise<WorkflowHandle<T>>;
|
|
468
|
+
|
|
469
|
+
constructor(
|
|
470
|
+
public workflowTypeOrFunc: string | T,
|
|
471
|
+
public options: WorkflowStartOptions<T> & { workflowIdConflictPolicy: WorkflowIdConflictPolicy }
|
|
472
|
+
) {
|
|
473
|
+
this.workflowHandlePromise = new Promise<WorkflowHandle<T>>((resolve, reject) => {
|
|
474
|
+
this[withStartWorkflowOperationResolve] = resolve;
|
|
475
|
+
this[withStartWorkflowOperationReject] = reject;
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
public async workflowHandle(): Promise<WorkflowHandle<T>> {
|
|
480
|
+
return await this.workflowHandlePromise;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
453
484
|
/**
|
|
454
485
|
* Client for starting Workflow executions and creating Workflow handles.
|
|
455
486
|
*
|
|
@@ -478,11 +509,6 @@ export class WorkflowClient extends BaseClient {
|
|
|
478
509
|
return this.connection.workflowService;
|
|
479
510
|
}
|
|
480
511
|
|
|
481
|
-
/**
|
|
482
|
-
* Start a new Workflow execution.
|
|
483
|
-
*
|
|
484
|
-
* @returns the execution's `runId`.
|
|
485
|
-
*/
|
|
486
512
|
protected async _start<T extends Workflow>(
|
|
487
513
|
workflowTypeOrFunc: string | T,
|
|
488
514
|
options: WithWorkflowArgs<T, WorkflowOptions>,
|
|
@@ -501,12 +527,6 @@ export class WorkflowClient extends BaseClient {
|
|
|
501
527
|
});
|
|
502
528
|
}
|
|
503
529
|
|
|
504
|
-
/**
|
|
505
|
-
* Sends a signal to a running Workflow or starts a new one if not already running and immediately signals it.
|
|
506
|
-
* Useful when you're unsure of the Workflow's run state.
|
|
507
|
-
*
|
|
508
|
-
* @returns the runId of the Workflow
|
|
509
|
-
*/
|
|
510
530
|
protected async _signalWithStart<T extends Workflow, SA extends any[]>(
|
|
511
531
|
workflowTypeOrFunc: string | T,
|
|
512
532
|
options: WithWorkflowArgs<T, WorkflowSignalWithStartOptions<SA>>,
|
|
@@ -535,7 +555,7 @@ export class WorkflowClient extends BaseClient {
|
|
|
535
555
|
/**
|
|
536
556
|
* Start a new Workflow execution.
|
|
537
557
|
*
|
|
538
|
-
* @returns a WorkflowHandle to the started Workflow
|
|
558
|
+
* @returns a {@link WorkflowHandle} to the started Workflow
|
|
539
559
|
*/
|
|
540
560
|
public async start<T extends Workflow>(
|
|
541
561
|
workflowTypeOrFunc: string | T,
|
|
@@ -559,8 +579,13 @@ export class WorkflowClient extends BaseClient {
|
|
|
559
579
|
}
|
|
560
580
|
|
|
561
581
|
/**
|
|
562
|
-
*
|
|
563
|
-
*
|
|
582
|
+
* Start a new Workflow Execution and immediately send a Signal to that Workflow.
|
|
583
|
+
*
|
|
584
|
+
* The behavior of Signal-with-Start in the case where there is already a running Workflow with
|
|
585
|
+
* the given Workflow ID depends on the {@link WorkflowIDConflictPolicy}. That is, if the policy
|
|
586
|
+
* is `USE_EXISTING`, then the Signal is issued against the already existing Workflow Execution;
|
|
587
|
+
* however, if the policy is `FAIL`, then an error is thrown. If no policy is specified,
|
|
588
|
+
* Signal-with-Start defaults to `USE_EXISTING`.
|
|
564
589
|
*
|
|
565
590
|
* @returns a {@link WorkflowHandle} to the started Workflow
|
|
566
591
|
*/
|
|
@@ -586,7 +611,141 @@ export class WorkflowClient extends BaseClient {
|
|
|
586
611
|
}
|
|
587
612
|
|
|
588
613
|
/**
|
|
589
|
-
*
|
|
614
|
+
* Start a new Workflow Execution and immediately send an Update to that Workflow,
|
|
615
|
+
* then await and return the Update's result.
|
|
616
|
+
*
|
|
617
|
+
* The `updateOptions` object must contain a {@link WithStartWorkflowOperation}, which defines
|
|
618
|
+
* the options for the Workflow execution to start (e.g. the Workflow's type, task queue, input
|
|
619
|
+
* arguments, etc.)
|
|
620
|
+
*
|
|
621
|
+
* The behavior of Update-with-Start in the case where there is already a running Workflow with
|
|
622
|
+
* the given Workflow ID depends on the specified {@link WorkflowIDConflictPolicy}. That is, if
|
|
623
|
+
* the policy is `USE_EXISTING`, then the Update is issued against the already existing Workflow
|
|
624
|
+
* Execution; however, if the policy is `FAIL`, then an error is thrown. Caller MUST specify
|
|
625
|
+
* the desired WorkflowIDConflictPolicy.
|
|
626
|
+
*
|
|
627
|
+
* This call will block until the Update has completed. The Workflow handle can be retrieved by
|
|
628
|
+
* awaiting on {@link WithStartWorkflowOperation.workflowHandle}, whether or not the Update
|
|
629
|
+
* succeeds.
|
|
630
|
+
*
|
|
631
|
+
* @returns the Update result
|
|
632
|
+
*
|
|
633
|
+
* @experimental Update-with-Start is an experimental feature and may be subject to change.
|
|
634
|
+
*/
|
|
635
|
+
public async executeUpdateWithStart<T extends Workflow, Ret, Args extends any[]>(
|
|
636
|
+
updateDef: UpdateDefinition<Ret, Args> | string,
|
|
637
|
+
updateOptions: WorkflowUpdateOptions & { args?: Args; startWorkflowOperation: WithStartWorkflowOperation<T> }
|
|
638
|
+
): Promise<Ret> {
|
|
639
|
+
const handle = await this._startUpdateWithStart(updateDef, {
|
|
640
|
+
...updateOptions,
|
|
641
|
+
waitForStage: WorkflowUpdateStage.COMPLETED,
|
|
642
|
+
});
|
|
643
|
+
return await handle.result();
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Start a new Workflow Execution and immediately send an Update to that Workflow,
|
|
648
|
+
* then return a {@link WorkflowUpdateHandle} for that Update.
|
|
649
|
+
*
|
|
650
|
+
* The `updateOptions` object must contain a {@link WithStartWorkflowOperation}, which defines
|
|
651
|
+
* the options for the Workflow execution to start (e.g. the Workflow's type, task queue, input
|
|
652
|
+
* arguments, etc.)
|
|
653
|
+
*
|
|
654
|
+
* The behavior of Update-with-Start in the case where there is already a running Workflow with
|
|
655
|
+
* the given Workflow ID depends on the specified {@link WorkflowIDConflictPolicy}. That is, if
|
|
656
|
+
* the policy is `USE_EXISTING`, then the Update is issued against the already existing Workflow
|
|
657
|
+
* Execution; however, if the policy is `FAIL`, then an error is thrown. Caller MUST specify
|
|
658
|
+
* the desired WorkflowIDConflictPolicy.
|
|
659
|
+
*
|
|
660
|
+
* This call will block until the Update has reached the specified {@link WorkflowUpdateStage}.
|
|
661
|
+
* Note that this means that the call will not return successfully until the Update has
|
|
662
|
+
* been delivered to a Worker. The Workflow handle can be retrieved by awaiting on
|
|
663
|
+
* {@link WithStartWorkflowOperation.workflowHandle}, whether or not the Update succeeds.
|
|
664
|
+
*
|
|
665
|
+
* @returns a {@link WorkflowUpdateHandle} to the started Update
|
|
666
|
+
*
|
|
667
|
+
* @experimental Update-with-Start is an experimental feature and may be subject to change.
|
|
668
|
+
*/
|
|
669
|
+
public async startUpdateWithStart<T extends Workflow, Ret, Args extends any[]>(
|
|
670
|
+
updateDef: UpdateDefinition<Ret, Args> | string,
|
|
671
|
+
updateOptions: WorkflowUpdateOptions & {
|
|
672
|
+
args?: Args;
|
|
673
|
+
waitForStage: 'ACCEPTED';
|
|
674
|
+
startWorkflowOperation: WithStartWorkflowOperation<T>;
|
|
675
|
+
}
|
|
676
|
+
): Promise<WorkflowUpdateHandle<Ret>> {
|
|
677
|
+
return this._startUpdateWithStart(updateDef, updateOptions);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
protected async _startUpdateWithStart<T extends Workflow, Ret, Args extends any[]>(
|
|
681
|
+
updateDef: UpdateDefinition<Ret, Args> | string,
|
|
682
|
+
updateWithStartOptions: WorkflowUpdateOptions & {
|
|
683
|
+
args?: Args;
|
|
684
|
+
waitForStage: WorkflowUpdateStage;
|
|
685
|
+
startWorkflowOperation: WithStartWorkflowOperation<T>;
|
|
686
|
+
}
|
|
687
|
+
): Promise<WorkflowUpdateHandle<Ret>> {
|
|
688
|
+
const { waitForStage, args, startWorkflowOperation, ...updateOptions } = updateWithStartOptions;
|
|
689
|
+
const { workflowTypeOrFunc, options: workflowOptions } = startWorkflowOperation;
|
|
690
|
+
const { workflowId } = workflowOptions;
|
|
691
|
+
|
|
692
|
+
if (startWorkflowOperation[withStartWorkflowOperationUsed]) {
|
|
693
|
+
throw new Error('This WithStartWorkflowOperation instance has already been executed.');
|
|
694
|
+
}
|
|
695
|
+
startWorkflowOperation[withStartWorkflowOperationUsed] = true;
|
|
696
|
+
assertRequiredWorkflowOptions(workflowOptions);
|
|
697
|
+
|
|
698
|
+
const startUpdateWithStartInput: WorkflowStartUpdateWithStartInput = {
|
|
699
|
+
workflowType: extractWorkflowType(workflowTypeOrFunc),
|
|
700
|
+
workflowStartOptions: compileWorkflowOptions(ensureArgs(workflowOptions)),
|
|
701
|
+
workflowStartHeaders: {},
|
|
702
|
+
updateName: typeof updateDef === 'string' ? updateDef : updateDef.name,
|
|
703
|
+
updateArgs: args ?? [],
|
|
704
|
+
updateOptions,
|
|
705
|
+
updateHeaders: {},
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
const interceptors = this.getOrMakeInterceptors(workflowId);
|
|
709
|
+
|
|
710
|
+
const onStart = (startResponse: temporal.api.workflowservice.v1.IStartWorkflowExecutionResponse) =>
|
|
711
|
+
startWorkflowOperation[withStartWorkflowOperationResolve]!(
|
|
712
|
+
this._createWorkflowHandle({
|
|
713
|
+
workflowId,
|
|
714
|
+
firstExecutionRunId: startResponse.runId ?? undefined,
|
|
715
|
+
interceptors,
|
|
716
|
+
followRuns: workflowOptions.followRuns ?? true,
|
|
717
|
+
})
|
|
718
|
+
);
|
|
719
|
+
|
|
720
|
+
const onStartError = (err: any) => {
|
|
721
|
+
startWorkflowOperation[withStartWorkflowOperationReject]!(err);
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
const fn = composeInterceptors(
|
|
725
|
+
interceptors,
|
|
726
|
+
'startUpdateWithStart',
|
|
727
|
+
this._updateWithStartHandler.bind(this, waitForStage, onStart, onStartError)
|
|
728
|
+
);
|
|
729
|
+
const updateOutput = await fn(startUpdateWithStartInput);
|
|
730
|
+
|
|
731
|
+
let outcome = updateOutput.updateOutcome;
|
|
732
|
+
if (!outcome && waitForStage === WorkflowUpdateStage.COMPLETED) {
|
|
733
|
+
outcome = await this._pollForUpdateOutcome(updateOutput.updateId, {
|
|
734
|
+
workflowId,
|
|
735
|
+
runId: updateOutput.workflowExecution.runId,
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
return this.createWorkflowUpdateHandle<Ret>(
|
|
740
|
+
updateOutput.updateId,
|
|
741
|
+
workflowId,
|
|
742
|
+
updateOutput.workflowExecution.runId,
|
|
743
|
+
outcome
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Start a new Workflow execution, then await for its completion and return that Workflow's result.
|
|
590
749
|
*
|
|
591
750
|
* @returns the result of the Workflow execution
|
|
592
751
|
*/
|
|
@@ -604,9 +763,9 @@ export class WorkflowClient extends BaseClient {
|
|
|
604
763
|
}
|
|
605
764
|
|
|
606
765
|
/**
|
|
607
|
-
*
|
|
766
|
+
* Get the result of a Workflow execution.
|
|
608
767
|
*
|
|
609
|
-
*
|
|
768
|
+
* Follow the chain of execution in case Workflow continues as new, or has a cron schedule or retry policy.
|
|
610
769
|
*/
|
|
611
770
|
public async result<T extends Workflow>(
|
|
612
771
|
workflowId: string,
|
|
@@ -755,7 +914,7 @@ export class WorkflowClient extends BaseClient {
|
|
|
755
914
|
}
|
|
756
915
|
|
|
757
916
|
/**
|
|
758
|
-
*
|
|
917
|
+
* Use given input to make a queryWorkflow call to the service
|
|
759
918
|
*
|
|
760
919
|
* Used as the final function of the query interceptor chain
|
|
761
920
|
*/
|
|
@@ -795,31 +954,17 @@ export class WorkflowClient extends BaseClient {
|
|
|
795
954
|
return await decodeFromPayloadsAtIndex(this.dataConverter, 0, response.queryResult?.payloads);
|
|
796
955
|
}
|
|
797
956
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
*
|
|
801
|
-
* Used as the final function of the interceptor chain during startUpdate and executeUpdate.
|
|
802
|
-
*/
|
|
803
|
-
protected async _startUpdateHandler(
|
|
804
|
-
waitForStage: WorkflowUpdateStage,
|
|
957
|
+
protected async _createUpdateWorkflowRequest(
|
|
958
|
+
lifecycleStage: temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage,
|
|
805
959
|
input: WorkflowStartUpdateInput
|
|
806
|
-
): Promise<
|
|
807
|
-
let waitForStageProto: temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage =
|
|
808
|
-
encodeWorkflowUpdateStage(waitForStage) ??
|
|
809
|
-
UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED;
|
|
810
|
-
|
|
811
|
-
waitForStageProto =
|
|
812
|
-
waitForStageProto >= UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED
|
|
813
|
-
? waitForStageProto
|
|
814
|
-
: UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED;
|
|
815
|
-
|
|
960
|
+
): Promise<temporal.api.workflowservice.v1.IUpdateWorkflowExecutionRequest> {
|
|
816
961
|
const updateId = input.options?.updateId ?? uuid4();
|
|
817
|
-
|
|
962
|
+
return {
|
|
818
963
|
namespace: this.options.namespace,
|
|
819
964
|
workflowExecution: input.workflowExecution,
|
|
820
965
|
firstExecutionRunId: input.firstExecutionRunId,
|
|
821
966
|
waitPolicy: {
|
|
822
|
-
lifecycleStage
|
|
967
|
+
lifecycleStage,
|
|
823
968
|
},
|
|
824
969
|
request: {
|
|
825
970
|
meta: {
|
|
@@ -833,26 +978,140 @@ export class WorkflowClient extends BaseClient {
|
|
|
833
978
|
},
|
|
834
979
|
},
|
|
835
980
|
};
|
|
981
|
+
}
|
|
836
982
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
983
|
+
/**
|
|
984
|
+
* Start the Update.
|
|
985
|
+
*
|
|
986
|
+
* Used as the final function of the interceptor chain during startUpdate and executeUpdate.
|
|
987
|
+
*/
|
|
988
|
+
protected async _startUpdateHandler(
|
|
989
|
+
waitForStage: WorkflowUpdateStage,
|
|
990
|
+
input: WorkflowStartUpdateInput
|
|
991
|
+
): Promise<WorkflowStartUpdateOutput> {
|
|
992
|
+
let waitForStageProto: temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage =
|
|
993
|
+
encodeWorkflowUpdateStage(waitForStage) ??
|
|
994
|
+
UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED;
|
|
995
|
+
|
|
996
|
+
waitForStageProto =
|
|
997
|
+
waitForStageProto >= UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED
|
|
998
|
+
? waitForStageProto
|
|
999
|
+
: UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED;
|
|
1000
|
+
|
|
1001
|
+
const request = await this._createUpdateWorkflowRequest(waitForStageProto, input);
|
|
1002
|
+
|
|
1003
|
+
// Repeatedly send UpdateWorkflowExecution until update is durable (if the server receives a request with
|
|
1004
|
+
// an update ID that already exists, it responds with information for the existing update). If the
|
|
1005
|
+
// requested wait stage is COMPLETED, further polling is done before returning the UpdateHandle.
|
|
840
1006
|
let response: temporal.api.workflowservice.v1.UpdateWorkflowExecutionResponse;
|
|
841
1007
|
try {
|
|
842
1008
|
do {
|
|
843
|
-
response = await this.workflowService.updateWorkflowExecution(
|
|
844
|
-
} while (
|
|
1009
|
+
response = await this.workflowService.updateWorkflowExecution(request);
|
|
1010
|
+
} while (
|
|
1011
|
+
response.stage < UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED
|
|
1012
|
+
);
|
|
845
1013
|
} catch (err) {
|
|
846
1014
|
this.rethrowUpdateGrpcError(err, 'Workflow Update failed', input.workflowExecution);
|
|
847
1015
|
}
|
|
848
1016
|
return {
|
|
849
|
-
updateId
|
|
1017
|
+
updateId: request.request!.meta!.updateId!,
|
|
850
1018
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
851
1019
|
workflowRunId: response.updateRef!.workflowExecution!.runId!,
|
|
852
1020
|
outcome: response.outcome ?? undefined,
|
|
853
1021
|
};
|
|
854
1022
|
}
|
|
855
1023
|
|
|
1024
|
+
/**
|
|
1025
|
+
* Send the Update-With-Start MultiOperation request.
|
|
1026
|
+
*
|
|
1027
|
+
* Used as the final function of the interceptor chain during
|
|
1028
|
+
* startUpdateWithStart and executeUpdateWithStart.
|
|
1029
|
+
*/
|
|
1030
|
+
protected async _updateWithStartHandler(
|
|
1031
|
+
waitForStage: WorkflowUpdateStage,
|
|
1032
|
+
onStart: (startResponse: temporal.api.workflowservice.v1.IStartWorkflowExecutionResponse) => void,
|
|
1033
|
+
onStartError: (err: any) => void,
|
|
1034
|
+
input: WorkflowStartUpdateWithStartInput
|
|
1035
|
+
): Promise<WorkflowStartUpdateWithStartOutput> {
|
|
1036
|
+
const startInput: WorkflowStartInput = {
|
|
1037
|
+
workflowType: input.workflowType,
|
|
1038
|
+
options: input.workflowStartOptions,
|
|
1039
|
+
headers: input.workflowStartHeaders,
|
|
1040
|
+
};
|
|
1041
|
+
const updateInput: WorkflowStartUpdateInput = {
|
|
1042
|
+
updateName: input.updateName,
|
|
1043
|
+
args: input.updateArgs,
|
|
1044
|
+
workflowExecution: {
|
|
1045
|
+
workflowId: input.workflowStartOptions.workflowId,
|
|
1046
|
+
},
|
|
1047
|
+
options: input.updateOptions,
|
|
1048
|
+
headers: input.updateHeaders,
|
|
1049
|
+
};
|
|
1050
|
+
let seenStart = false;
|
|
1051
|
+
try {
|
|
1052
|
+
const startRequest = await this.createStartWorkflowRequest(startInput);
|
|
1053
|
+
const waitForStageProto = encodeWorkflowUpdateStage(waitForStage)!;
|
|
1054
|
+
const updateRequest = await this._createUpdateWorkflowRequest(waitForStageProto, updateInput);
|
|
1055
|
+
const multiOpReq: temporal.api.workflowservice.v1.IExecuteMultiOperationRequest = {
|
|
1056
|
+
namespace: this.options.namespace,
|
|
1057
|
+
operations: [
|
|
1058
|
+
{
|
|
1059
|
+
startWorkflow: startRequest,
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
updateWorkflow: updateRequest,
|
|
1063
|
+
},
|
|
1064
|
+
],
|
|
1065
|
+
};
|
|
1066
|
+
|
|
1067
|
+
let multiOpResp: temporal.api.workflowservice.v1.IExecuteMultiOperationResponse;
|
|
1068
|
+
let startResp: temporal.api.workflowservice.v1.IStartWorkflowExecutionResponse;
|
|
1069
|
+
let updateResp: temporal.api.workflowservice.v1.IUpdateWorkflowExecutionResponse;
|
|
1070
|
+
let reachedStage: temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage;
|
|
1071
|
+
// Repeatedly send ExecuteMultiOperation until update is durable (if the server receives a request with
|
|
1072
|
+
// an update ID that already exists, it responds with information for the existing update). If the
|
|
1073
|
+
// requested wait stage is COMPLETED, further polling is done before returning the UpdateHandle.
|
|
1074
|
+
do {
|
|
1075
|
+
multiOpResp = await this.workflowService.executeMultiOperation(multiOpReq);
|
|
1076
|
+
startResp = multiOpResp.responses?.[0]
|
|
1077
|
+
?.startWorkflow as temporal.api.workflowservice.v1.IStartWorkflowExecutionResponse;
|
|
1078
|
+
if (!seenStart) {
|
|
1079
|
+
onStart(startResp);
|
|
1080
|
+
seenStart = true;
|
|
1081
|
+
}
|
|
1082
|
+
updateResp = multiOpResp.responses?.[1]
|
|
1083
|
+
?.updateWorkflow as temporal.api.workflowservice.v1.IUpdateWorkflowExecutionResponse;
|
|
1084
|
+
reachedStage =
|
|
1085
|
+
updateResp.stage ??
|
|
1086
|
+
UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_UNSPECIFIED;
|
|
1087
|
+
} while (reachedStage < UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ACCEPTED);
|
|
1088
|
+
return {
|
|
1089
|
+
workflowExecution: {
|
|
1090
|
+
workflowId: updateResp.updateRef!.workflowExecution!.workflowId!,
|
|
1091
|
+
runId: updateResp.updateRef!.workflowExecution!.runId!,
|
|
1092
|
+
},
|
|
1093
|
+
updateId: updateRequest.request!.meta!.updateId!,
|
|
1094
|
+
updateOutcome: updateResp.outcome ?? undefined,
|
|
1095
|
+
};
|
|
1096
|
+
} catch (thrownError) {
|
|
1097
|
+
let err = thrownError;
|
|
1098
|
+
if (isGrpcServiceError(err) && err.code === grpcStatus.ALREADY_EXISTS) {
|
|
1099
|
+
err = new WorkflowExecutionAlreadyStartedError(
|
|
1100
|
+
'Workflow execution already started',
|
|
1101
|
+
input.workflowStartOptions.workflowId,
|
|
1102
|
+
input.workflowType
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1105
|
+
if (!seenStart) {
|
|
1106
|
+
onStartError(err);
|
|
1107
|
+
}
|
|
1108
|
+
if (isGrpcServiceError(err)) {
|
|
1109
|
+
this.rethrowUpdateGrpcError(err, 'Update-With-Start failed', updateInput.workflowExecution);
|
|
1110
|
+
}
|
|
1111
|
+
throw err;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
|
|
856
1115
|
protected createWorkflowUpdateHandle<Ret>(
|
|
857
1116
|
updateId: string,
|
|
858
1117
|
workflowId: string,
|
|
@@ -908,7 +1167,7 @@ export class WorkflowClient extends BaseClient {
|
|
|
908
1167
|
}
|
|
909
1168
|
|
|
910
1169
|
/**
|
|
911
|
-
*
|
|
1170
|
+
* Use given input to make a signalWorkflowExecution call to the service
|
|
912
1171
|
*
|
|
913
1172
|
* Used as the final function of the signal interceptor chain
|
|
914
1173
|
*/
|
|
@@ -931,7 +1190,7 @@ export class WorkflowClient extends BaseClient {
|
|
|
931
1190
|
}
|
|
932
1191
|
|
|
933
1192
|
/**
|
|
934
|
-
*
|
|
1193
|
+
* Use given input to make a signalWithStartWorkflowExecution call to the service
|
|
935
1194
|
*
|
|
936
1195
|
* Used as the final function of the signalWithStart interceptor chain
|
|
937
1196
|
*/
|
|
@@ -982,15 +1241,32 @@ export class WorkflowClient extends BaseClient {
|
|
|
982
1241
|
}
|
|
983
1242
|
|
|
984
1243
|
/**
|
|
985
|
-
*
|
|
1244
|
+
* Use given input to make startWorkflowExecution call to the service
|
|
986
1245
|
*
|
|
987
1246
|
* Used as the final function of the start interceptor chain
|
|
988
1247
|
*/
|
|
989
1248
|
protected async _startWorkflowHandler(input: WorkflowStartInput): Promise<string> {
|
|
1249
|
+
const req = await this.createStartWorkflowRequest(input);
|
|
1250
|
+
const { options: opts, workflowType } = input;
|
|
1251
|
+
try {
|
|
1252
|
+
return (await this.workflowService.startWorkflowExecution(req)).runId;
|
|
1253
|
+
} catch (err: any) {
|
|
1254
|
+
if (err.code === grpcStatus.ALREADY_EXISTS) {
|
|
1255
|
+
throw new WorkflowExecutionAlreadyStartedError(
|
|
1256
|
+
'Workflow execution already started',
|
|
1257
|
+
opts.workflowId,
|
|
1258
|
+
workflowType
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
this.rethrowGrpcError(err, 'Failed to start Workflow', { workflowId: opts.workflowId });
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
protected async createStartWorkflowRequest(input: WorkflowStartInput): Promise<StartWorkflowExecutionRequest> {
|
|
990
1266
|
const { options: opts, workflowType, headers } = input;
|
|
991
|
-
const { identity } = this.options;
|
|
992
|
-
|
|
993
|
-
namespace
|
|
1267
|
+
const { identity, namespace } = this.options;
|
|
1268
|
+
return {
|
|
1269
|
+
namespace,
|
|
994
1270
|
identity,
|
|
995
1271
|
requestId: uuid4(),
|
|
996
1272
|
workflowId: opts.workflowId,
|
|
@@ -1016,22 +1292,10 @@ export class WorkflowClient extends BaseClient {
|
|
|
1016
1292
|
cronSchedule: opts.cronSchedule,
|
|
1017
1293
|
header: { fields: headers },
|
|
1018
1294
|
};
|
|
1019
|
-
try {
|
|
1020
|
-
return (await this.workflowService.startWorkflowExecution(req)).runId;
|
|
1021
|
-
} catch (err: any) {
|
|
1022
|
-
if (err.code === grpcStatus.ALREADY_EXISTS) {
|
|
1023
|
-
throw new WorkflowExecutionAlreadyStartedError(
|
|
1024
|
-
'Workflow execution already started',
|
|
1025
|
-
opts.workflowId,
|
|
1026
|
-
workflowType
|
|
1027
|
-
);
|
|
1028
|
-
}
|
|
1029
|
-
this.rethrowGrpcError(err, 'Failed to start Workflow', { workflowId: opts.workflowId });
|
|
1030
|
-
}
|
|
1031
1295
|
}
|
|
1032
1296
|
|
|
1033
1297
|
/**
|
|
1034
|
-
*
|
|
1298
|
+
* Use given input to make terminateWorkflowExecution call to the service
|
|
1035
1299
|
*
|
|
1036
1300
|
* Used as the final function of the terminate interceptor chain
|
|
1037
1301
|
*/
|
|
@@ -1285,9 +1549,9 @@ export class WorkflowClient extends BaseClient {
|
|
|
1285
1549
|
}
|
|
1286
1550
|
|
|
1287
1551
|
/**
|
|
1288
|
-
*
|
|
1552
|
+
* Return a list of Workflow Executions matching the given `query`.
|
|
1289
1553
|
*
|
|
1290
|
-
*
|
|
1554
|
+
* Note that the list of Workflow Executions returned is approximate and eventually consistent.
|
|
1291
1555
|
*
|
|
1292
1556
|
* More info on the concept of "visibility" and the query syntax on the Temporal documentation site:
|
|
1293
1557
|
* https://docs.temporal.io/visibility
|
|
@@ -1308,6 +1572,29 @@ export class WorkflowClient extends BaseClient {
|
|
|
1308
1572
|
};
|
|
1309
1573
|
}
|
|
1310
1574
|
|
|
1575
|
+
/**
|
|
1576
|
+
* Return the number of Workflow Executions matching the given `query`. If no `query` is provided, then return the
|
|
1577
|
+
* total number of Workflow Executions for this namespace.
|
|
1578
|
+
*
|
|
1579
|
+
* Note that the number of Workflow Executions returned is approximate and eventually consistent.
|
|
1580
|
+
*
|
|
1581
|
+
* More info on the concept of "visibility" and the query syntax on the Temporal documentation site:
|
|
1582
|
+
* https://docs.temporal.io/visibility
|
|
1583
|
+
*/
|
|
1584
|
+
public async count(query?: string): Promise<CountWorkflowExecution> {
|
|
1585
|
+
let response: temporal.api.workflowservice.v1.CountWorkflowExecutionsResponse;
|
|
1586
|
+
try {
|
|
1587
|
+
response = await this.workflowService.countWorkflowExecutions({
|
|
1588
|
+
namespace: this.options.namespace,
|
|
1589
|
+
query,
|
|
1590
|
+
});
|
|
1591
|
+
} catch (e) {
|
|
1592
|
+
this.rethrowGrpcError(e, 'Failed to count workflows');
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
return decodeCountWorkflowExecutionsResponse(response);
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1311
1598
|
protected getOrMakeInterceptors(workflowId: string, runId?: string): WorkflowClientInterceptor[] {
|
|
1312
1599
|
if (typeof this.options.interceptors === 'object' && 'calls' in this.options.interceptors) {
|
|
1313
1600
|
// eslint-disable-next-line deprecation/deprecation
|