@@ -5,12 +5,10 @@ import {
5
5
compileRetryPolicy ,
6
6
DataConverter ,
7
7
LoadedDataConverter ,
8
- mapFromPayloads ,
9
8
mapToPayloads ,
10
9
QueryDefinition ,
11
10
RetryState ,
12
11
searchAttributePayloadConverter ,
13
- SearchAttributes ,
14
12
SignalDefinition ,
15
13
TerminatedFailure ,
16
14
TimeoutFailure ,
@@ -21,12 +19,10 @@ import {
21
19
WorkflowNotFoundError ,
22
20
WorkflowResultType ,
23
21
} from '@temporalio/common' ;
24
- import { tsToDate , optionalTsToDate } from '@temporalio/common/lib/time' ;
25
22
import { composeInterceptors } from '@temporalio/common/lib/interceptors' ;
26
23
import {
27
24
decodeArrayFromPayloads ,
28
25
decodeFromPayloadsAtIndex ,
29
- decodeMapFromPayloads ,
30
26
decodeOptionalFailureToOptionalError ,
31
27
encodeMapToPayloads ,
32
28
encodeToPayloads ,
@@ -61,10 +57,11 @@ import {
61
57
TerminateWorkflowExecutionResponse ,
62
58
WorkflowExecution ,
63
59
WorkflowExecutionDescription ,
64
- WorkflowExecutionStatusName ,
60
+ WorkflowExecutionInfo ,
65
61
WorkflowService ,
66
62
} from './types' ;
67
63
import { compileWorkflowOptions , WorkflowOptions , WorkflowSignalWithStartOptions } from './workflow-options' ;
64
+ import { executionInfoFromRaw } from './helpers' ;
68
65
69
66
/**
70
67
* A client side handle to a single Workflow instance.
@@ -288,6 +285,22 @@ interface WorkflowHandleOptions extends GetWorkflowHandleOptions {
288
285
*/
289
286
export type WorkflowStartOptions < T extends Workflow = Workflow > = WithWorkflowArgs < T , WorkflowOptions > ;
290
287
288
+ /**
289
+ * Options for {@link WorkflowClient.list}
290
+ */
291
+ export interface ListOptions {
292
+ /**
293
+ * Maximum number of results to fetch per page.
294
+ *
295
+ * @default depends on server config, typically 1000
296
+ */
297
+ pageSize ?: number ;
298
+ /**
299
+ * Query string for matching and ordering the results
300
+ */
301
+ query ?: string ;
302
+ }
303
+
291
304
/**
292
305
* Client for starting Workflow executions and creating Workflow handles.
293
306
*
@@ -848,38 +861,9 @@ export class WorkflowClient {
848
861
const raw = await fn ( {
849
862
workflowExecution : { workflowId, runId } ,
850
863
} ) ;
851
- return {
852
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
853
- type : raw . workflowExecutionInfo ! . type ! . name ! ,
854
- workflowId : raw . workflowExecutionInfo ! . execution ! . workflowId ! ,
855
- runId : raw . workflowExecutionInfo ! . execution ! . runId ! ,
856
- taskQueue : raw . workflowExecutionInfo ! . taskQueue ! ,
857
- status : {
858
- code : raw . workflowExecutionInfo ! . status ! ,
859
- name : workflowStatusCodeToName ( raw . workflowExecutionInfo ! . status ! ) ,
860
- } ,
861
- // Safe to convert to number, max history length is 50k, which is much less than Number.MAX_SAFE_INTEGER
862
- historyLength : raw . workflowExecutionInfo ! . historyLength ! . toNumber ( ) ,
863
- startTime : tsToDate ( raw . workflowExecutionInfo ! . startTime ! ) ,
864
- executionTime : optionalTsToDate ( raw . workflowExecutionInfo ! . executionTime ) ,
865
- closeTime : optionalTsToDate ( raw . workflowExecutionInfo ! . closeTime ) ,
866
- memo : await decodeMapFromPayloads ( this . client . dataConverter , raw . workflowExecutionInfo ! . memo ?. fields ) ,
867
- searchAttributes : Object . fromEntries (
868
- Object . entries (
869
- mapFromPayloads (
870
- searchAttributePayloadConverter ,
871
- raw . workflowExecutionInfo ! . searchAttributes ?. indexedFields ?? { }
872
- ) as SearchAttributes
873
- ) . filter ( ( [ _ , v ] ) => v && v . length > 0 ) // Filter out empty arrays returned by pre 1.18 servers
874
- ) ,
875
- parentExecution : raw . workflowExecutionInfo ?. parentExecution
876
- ? {
877
- workflowId : raw . workflowExecutionInfo . parentExecution . workflowId ! ,
878
- runId : raw . workflowExecutionInfo . parentExecution . runId ! ,
879
- }
880
- : undefined ,
881
- raw,
882
- } ;
864
+ const info = await executionInfoFromRaw ( raw . workflowExecutionInfo ?? { } , this . client . dataConverter ) ;
865
+ ( info as unknown as WorkflowExecutionDescription ) . raw = raw ;
866
+ return info ;
883
867
} ,
884
868
async signal < Args extends any [ ] > ( def : SignalDefinition < Args > | string , ...args : Args ) : Promise < void > {
885
869
const next = this . client . _signalWorkflowHandler . bind ( this . client ) ;
@@ -939,6 +923,34 @@ export class WorkflowClient {
939
923
followRuns : options ?. followRuns ?? true ,
940
924
} ) ;
941
925
}
926
+
927
+ /**
928
+ * List workflows by given `query`.
929
+ *
930
+ * ⚠️ To use advanced query functionality, as of the 1.18 server release, you must use Elasticsearch based visibility.
931
+ *
932
+ * More info on the concept of "visibility" and the query syntax on the Temporal documentation site:
933
+ * https://docs.temporal.io/visibility
934
+ */
935
+ public async * list ( options ?: ListOptions ) : AsyncIterable < WorkflowExecutionInfo > {
936
+ let nextPageToken : Uint8Array = Buffer . alloc ( 0 ) ;
937
+ for ( ; ; ) {
938
+ const response = await this . workflowService . listWorkflowExecutions ( {
939
+ namespace : this . options . namespace ,
940
+ query : options ?. query ,
941
+ nextPageToken,
942
+ pageSize : options ?. pageSize ,
943
+ } ) ;
944
+ // Not decoding memo payloads concurrently even though we could have to keep the lazy nature of this iterator.
945
+ // Decoding is done for `memo` fields which tend to be small.
946
+ // We might decide to change that based on user feedback.
947
+ for ( const raw of response . executions ) {
948
+ yield await executionInfoFromRaw ( raw , this . dataConverter ) ;
949
+ }
950
+ nextPageToken = response . nextPageToken ;
951
+ if ( nextPageToken == null || nextPageToken . length == 0 ) break ;
952
+ }
953
+ }
942
954
}
943
955
944
956
export class QueryRejectedError extends Error {
@@ -954,33 +966,3 @@ export class QueryNotRegisteredError extends Error {
954
966
super ( message ) ;
955
967
}
956
968
}
957
-
958
- function workflowStatusCodeToName ( code : temporal . api . enums . v1 . WorkflowExecutionStatus ) : WorkflowExecutionStatusName {
959
- return workflowStatusCodeToNameInternal ( code ) ?? 'UNKNOWN' ;
960
- }
961
-
962
- /**
963
- * Intentionally leave out `default` branch to get compilation errors when new values are added
964
- */
965
- function workflowStatusCodeToNameInternal (
966
- code : temporal . api . enums . v1 . WorkflowExecutionStatus
967
- ) : WorkflowExecutionStatusName {
968
- switch ( code ) {
969
- case temporal . api . enums . v1 . WorkflowExecutionStatus . WORKFLOW_EXECUTION_STATUS_UNSPECIFIED :
970
- return 'UNSPECIFIED' ;
971
- case temporal . api . enums . v1 . WorkflowExecutionStatus . WORKFLOW_EXECUTION_STATUS_RUNNING :
972
- return 'RUNNING' ;
973
- case temporal . api . enums . v1 . WorkflowExecutionStatus . WORKFLOW_EXECUTION_STATUS_FAILED :
974
- return 'FAILED' ;
975
- case temporal . api . enums . v1 . WorkflowExecutionStatus . WORKFLOW_EXECUTION_STATUS_TIMED_OUT :
976
- return 'TIMED_OUT' ;
977
- case temporal . api . enums . v1 . WorkflowExecutionStatus . WORKFLOW_EXECUTION_STATUS_CANCELED :
978
- return 'CANCELLED' ;
979
- case temporal . api . enums . v1 . WorkflowExecutionStatus . WORKFLOW_EXECUTION_STATUS_TERMINATED :
980
- return 'TERMINATED' ;
981
- case temporal . api . enums . v1 . WorkflowExecutionStatus . WORKFLOW_EXECUTION_STATUS_COMPLETED :
982
- return 'COMPLETED' ;
983
- case temporal . api . enums . v1 . WorkflowExecutionStatus . WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW :
984
- return 'CONTINUED_AS_NEW' ;
985
- }
986
- }
0 commit comments