@temporalio/workflow 1.12.1 → 1.12.3
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/interceptors.d.ts +6 -0
- package/lib/internals.d.ts +1 -0
- package/lib/internals.js +41 -11
- package/lib/internals.js.map +1 -1
- package/lib/workflow.d.ts +77 -9
- package/lib/workflow.js +65 -17
- package/lib/workflow.js.map +1 -1
- package/package.json +4 -4
- package/src/interceptors.ts +7 -0
- package/src/internals.ts +63 -23
- package/src/workflow.ts +152 -44
package/src/workflow.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
ActivityFunction,
|
|
3
3
|
ActivityOptions,
|
|
4
4
|
compileRetryPolicy,
|
|
5
|
+
compilePriority,
|
|
5
6
|
encodeActivityCancellationType,
|
|
6
7
|
encodeWorkflowIdReusePolicy,
|
|
7
8
|
extractWorkflowType,
|
|
@@ -22,9 +23,9 @@ import {
|
|
|
22
23
|
WorkflowReturnType,
|
|
23
24
|
WorkflowUpdateValidatorType,
|
|
24
25
|
SearchAttributeUpdatePair,
|
|
25
|
-
compilePriority,
|
|
26
26
|
WorkflowDefinitionOptionsOrGetter,
|
|
27
27
|
} from '@temporalio/common';
|
|
28
|
+
import { userMetadataToPayload } from '@temporalio/common/lib/user-metadata';
|
|
28
29
|
import {
|
|
29
30
|
encodeUnifiedSearchAttributes,
|
|
30
31
|
searchAttributePayloadConverter,
|
|
@@ -33,6 +34,8 @@ import { versioningIntentToProto } from '@temporalio/common/lib/versioning-inten
|
|
|
33
34
|
import { Duration, msOptionalToTs, msToNumber, msToTs, requiredTsToMs } from '@temporalio/common/lib/time';
|
|
34
35
|
import { composeInterceptors } from '@temporalio/common/lib/interceptors';
|
|
35
36
|
import { temporal } from '@temporalio/proto';
|
|
37
|
+
import { deepMerge } from '@temporalio/common/lib/internal-workflow';
|
|
38
|
+
import { throwIfReservedName } from '@temporalio/common/lib/reserved';
|
|
36
39
|
import { CancellationScope, registerSleepImplementation } from './cancellation-scope';
|
|
37
40
|
import { UpdateScope } from './update-scope';
|
|
38
41
|
import {
|
|
@@ -41,6 +44,7 @@ import {
|
|
|
41
44
|
SignalWorkflowInput,
|
|
42
45
|
StartChildWorkflowExecutionInput,
|
|
43
46
|
TimerInput,
|
|
47
|
+
TimerOptions,
|
|
44
48
|
} from './interceptors';
|
|
45
49
|
import {
|
|
46
50
|
ChildWorkflowCancellationType,
|
|
@@ -87,7 +91,7 @@ export function addDefaultWorkflowOptions<T extends Workflow>(
|
|
|
87
91
|
/**
|
|
88
92
|
* Push a startTimer command into state accumulator and register completion
|
|
89
93
|
*/
|
|
90
|
-
function timerNextHandler(
|
|
94
|
+
function timerNextHandler({ seq, durationMs, options }: TimerInput) {
|
|
91
95
|
const activator = getActivator();
|
|
92
96
|
return new Promise<void>((resolve, reject) => {
|
|
93
97
|
const scope = CancellationScope.current();
|
|
@@ -98,12 +102,12 @@ function timerNextHandler(input: TimerInput) {
|
|
|
98
102
|
if (scope.cancellable) {
|
|
99
103
|
untrackPromise(
|
|
100
104
|
scope.cancelRequested.catch((err) => {
|
|
101
|
-
if (!activator.completions.timer.delete(
|
|
105
|
+
if (!activator.completions.timer.delete(seq)) {
|
|
102
106
|
return; // Already resolved or never scheduled
|
|
103
107
|
}
|
|
104
108
|
activator.pushCommand({
|
|
105
109
|
cancelTimer: {
|
|
106
|
-
seq
|
|
110
|
+
seq,
|
|
107
111
|
},
|
|
108
112
|
});
|
|
109
113
|
reject(err);
|
|
@@ -112,11 +116,12 @@ function timerNextHandler(input: TimerInput) {
|
|
|
112
116
|
}
|
|
113
117
|
activator.pushCommand({
|
|
114
118
|
startTimer: {
|
|
115
|
-
seq
|
|
116
|
-
startToFireTimeout: msToTs(
|
|
119
|
+
seq,
|
|
120
|
+
startToFireTimeout: msToTs(durationMs),
|
|
117
121
|
},
|
|
122
|
+
userMetadata: userMetadataToPayload(activator.payloadConverter, options?.summary, undefined),
|
|
118
123
|
});
|
|
119
|
-
activator.completions.timer.set(
|
|
124
|
+
activator.completions.timer.set(seq, {
|
|
120
125
|
resolve,
|
|
121
126
|
reject,
|
|
122
127
|
});
|
|
@@ -130,8 +135,9 @@ function timerNextHandler(input: TimerInput) {
|
|
|
130
135
|
*
|
|
131
136
|
* @param ms sleep duration - number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}.
|
|
132
137
|
* If given a negative number or 0, value will be set to 1.
|
|
138
|
+
* @param options optional timer options for additional configuration
|
|
133
139
|
*/
|
|
134
|
-
export function sleep(ms: Duration): Promise<void> {
|
|
140
|
+
export function sleep(ms: Duration, options?: TimerOptions): Promise<void> {
|
|
135
141
|
const activator = assertInWorkflowContext('Workflow.sleep(...) may only be used from a Workflow Execution');
|
|
136
142
|
const seq = activator.nextSeqs.timer++;
|
|
137
143
|
|
|
@@ -142,6 +148,7 @@ export function sleep(ms: Duration): Promise<void> {
|
|
|
142
148
|
return execute({
|
|
143
149
|
durationMs,
|
|
144
150
|
seq,
|
|
151
|
+
options,
|
|
145
152
|
});
|
|
146
153
|
}
|
|
147
154
|
|
|
@@ -198,6 +205,7 @@ function scheduleActivityNextHandler({ options, args, headers, seq, activityType
|
|
|
198
205
|
versioningIntent: versioningIntentToProto(options.versioningIntent), // eslint-disable-line deprecation/deprecation
|
|
199
206
|
priority: options.priority ? compilePriority(options.priority) : undefined,
|
|
200
207
|
},
|
|
208
|
+
userMetadata: userMetadataToPayload(activator.payloadConverter, options.summary, undefined),
|
|
201
209
|
});
|
|
202
210
|
activator.completions.activity.set(seq, {
|
|
203
211
|
resolve,
|
|
@@ -263,6 +271,7 @@ async function scheduleLocalActivityNextHandler({
|
|
|
263
271
|
headers,
|
|
264
272
|
cancellationType: encodeActivityCancellationType(options.cancellationType),
|
|
265
273
|
},
|
|
274
|
+
userMetadata: userMetadataToPayload(activator.payloadConverter, options.summary, undefined),
|
|
266
275
|
});
|
|
267
276
|
activator.completions.activity.set(seq, {
|
|
268
277
|
resolve,
|
|
@@ -399,6 +408,7 @@ function startChildWorkflowExecutionNextHandler({
|
|
|
399
408
|
versioningIntent: versioningIntentToProto(options.versioningIntent), // eslint-disable-line deprecation/deprecation
|
|
400
409
|
priority: options.priority ? compilePriority(options.priority) : undefined,
|
|
401
410
|
},
|
|
411
|
+
userMetadata: userMetadataToPayload(activator.payloadConverter, options?.staticSummary, options?.staticDetails),
|
|
402
412
|
});
|
|
403
413
|
activator.completions.childWorkflowStart.set(seq, {
|
|
404
414
|
resolve,
|
|
@@ -501,7 +511,44 @@ export const NotAnActivityMethod = Symbol.for('__TEMPORAL_NOT_AN_ACTIVITY_METHOD
|
|
|
501
511
|
* ```
|
|
502
512
|
*/
|
|
503
513
|
export type ActivityInterfaceFor<T> = {
|
|
504
|
-
[K in keyof T]: T[K] extends ActivityFunction ? T[K] : typeof NotAnActivityMethod;
|
|
514
|
+
[K in keyof T]: T[K] extends ActivityFunction ? ActivityFunctionWithOptions<T[K]> : typeof NotAnActivityMethod;
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
export type ActivityFunctionWithOptions<T extends ActivityFunction> = T & {
|
|
518
|
+
/**
|
|
519
|
+
* Execute the activity, overriding its existing options with the
|
|
520
|
+
* provided options.
|
|
521
|
+
*
|
|
522
|
+
* @param options ActivityOptions
|
|
523
|
+
* @param args: list of arguments
|
|
524
|
+
* @returns return value of the activity
|
|
525
|
+
*
|
|
526
|
+
* @experimental executeWithOptions is a new method to provide call-site options
|
|
527
|
+
* and is subject to change
|
|
528
|
+
*/
|
|
529
|
+
executeWithOptions(options: ActivityOptions, args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* The local activity counterpart to {@link ActivityInterfaceFor}
|
|
534
|
+
*/
|
|
535
|
+
export type LocalActivityInterfaceFor<T> = {
|
|
536
|
+
[K in keyof T]: T[K] extends ActivityFunction ? LocalActivityFunctionWithOptions<T[K]> : typeof NotAnActivityMethod;
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
export type LocalActivityFunctionWithOptions<T extends ActivityFunction> = T & {
|
|
540
|
+
/**
|
|
541
|
+
* Run the local activity, overriding its existing options with the
|
|
542
|
+
* provided options.
|
|
543
|
+
*
|
|
544
|
+
* @param options LocalActivityOptions
|
|
545
|
+
* @param args: list of arguments
|
|
546
|
+
* @returns return value of the activity
|
|
547
|
+
*
|
|
548
|
+
* @experimental executeWithOptions is a new method to provide call-site options
|
|
549
|
+
* and is subject to change
|
|
550
|
+
*/
|
|
551
|
+
executeWithOptions(options: LocalActivityOptions, args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
|
|
505
552
|
};
|
|
506
553
|
|
|
507
554
|
/**
|
|
@@ -522,6 +569,20 @@ export type ActivityInterfaceFor<T> = {
|
|
|
522
569
|
* startToCloseTimeout: '30 minutes',
|
|
523
570
|
* });
|
|
524
571
|
*
|
|
572
|
+
* // Use activities with default options
|
|
573
|
+
* const result1 = await httpGet('http://example.com');
|
|
574
|
+
*
|
|
575
|
+
* // Override options for specific activity calls
|
|
576
|
+
* const result2 = await httpGet.executeWithOptions({
|
|
577
|
+
* staticSummary: 'Fetches data from external API',
|
|
578
|
+
* scheduleToCloseTimeout: '5m'
|
|
579
|
+
* }, ['http://api.example.com']);
|
|
580
|
+
*
|
|
581
|
+
* const result3 = await otherActivity.executeWithOptions({
|
|
582
|
+
* staticSummary: 'Processes the fetched data',
|
|
583
|
+
* taskQueue: 'special-task-queue'
|
|
584
|
+
* }, [data]);
|
|
585
|
+
*
|
|
525
586
|
* // Setup Activities from an explicit interface (e.g. when defined by another SDK)
|
|
526
587
|
* interface JavaActivities {
|
|
527
588
|
* httpGetFromJava(url: string): Promise<string>
|
|
@@ -538,6 +599,11 @@ export type ActivityInterfaceFor<T> = {
|
|
|
538
599
|
*
|
|
539
600
|
* export function execute(): Promise<void> {
|
|
540
601
|
* const response = await httpGet("http://example.com");
|
|
602
|
+
* // Or with custom options:
|
|
603
|
+
* const response2 = await httpGetFromJava.executeWithOptions({
|
|
604
|
+
* staticSummary: 'Java HTTP call with timeout override',
|
|
605
|
+
* startToCloseTimeout: '2m'
|
|
606
|
+
* }, ["http://fast-api.example.com"]);
|
|
541
607
|
* // ...
|
|
542
608
|
* }
|
|
543
609
|
* ```
|
|
@@ -548,19 +614,27 @@ export function proxyActivities<A = UntypedActivities>(options: ActivityOptions)
|
|
|
548
614
|
}
|
|
549
615
|
// Validate as early as possible for immediate user feedback
|
|
550
616
|
validateActivityOptions(options);
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
{
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
617
|
+
|
|
618
|
+
return new Proxy({} as ActivityInterfaceFor<A>, {
|
|
619
|
+
get(_, activityType) {
|
|
620
|
+
if (typeof activityType !== 'string') {
|
|
621
|
+
throw new TypeError(`Only strings are supported for Activity types, got: ${String(activityType)}`);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function activityProxyFunction(...args: unknown[]): Promise<unknown> {
|
|
625
|
+
return scheduleActivity(activityType as string, args, options);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
activityProxyFunction.executeWithOptions = function (
|
|
629
|
+
overrideOptions: ActivityOptions,
|
|
630
|
+
args: any[]
|
|
631
|
+
): Promise<unknown> {
|
|
632
|
+
return scheduleActivity(activityType, args, deepMerge(options, overrideOptions));
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
return activityProxyFunction;
|
|
636
|
+
},
|
|
637
|
+
});
|
|
564
638
|
}
|
|
565
639
|
|
|
566
640
|
/**
|
|
@@ -573,25 +647,35 @@ export function proxyActivities<A = UntypedActivities>(options: ActivityOptions)
|
|
|
573
647
|
*
|
|
574
648
|
* @see {@link proxyActivities} for examples
|
|
575
649
|
*/
|
|
576
|
-
export function proxyLocalActivities<A = UntypedActivities>(
|
|
650
|
+
export function proxyLocalActivities<A = UntypedActivities>(
|
|
651
|
+
options: LocalActivityOptions
|
|
652
|
+
): LocalActivityInterfaceFor<A> {
|
|
577
653
|
if (options === undefined) {
|
|
578
654
|
throw new TypeError('options must be defined');
|
|
579
655
|
}
|
|
580
656
|
// Validate as early as possible for immediate user feedback
|
|
581
657
|
validateLocalActivityOptions(options);
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
{
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
658
|
+
|
|
659
|
+
return new Proxy({} as LocalActivityInterfaceFor<A>, {
|
|
660
|
+
get(_, activityType) {
|
|
661
|
+
if (typeof activityType !== 'string') {
|
|
662
|
+
throw new TypeError(`Only strings are supported for Activity types, got: ${String(activityType)}`);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function localActivityProxyFunction(...args: unknown[]): Promise<unknown> {
|
|
666
|
+
return scheduleLocalActivity(activityType as string, args, options);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
localActivityProxyFunction.executeWithOptions = function (
|
|
670
|
+
overrideOptions: LocalActivityOptions,
|
|
671
|
+
args: any[]
|
|
672
|
+
): Promise<unknown> {
|
|
673
|
+
return scheduleLocalActivity(activityType, args, deepMerge(options, overrideOptions));
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
return localActivityProxyFunction;
|
|
677
|
+
},
|
|
678
|
+
});
|
|
595
679
|
}
|
|
596
680
|
|
|
597
681
|
// TODO: deprecate this patch after "enough" time has passed
|
|
@@ -961,13 +1045,13 @@ export function makeContinueAsNewFunc<F extends Workflow>(
|
|
|
961
1045
|
* @example
|
|
962
1046
|
*
|
|
963
1047
|
* ```ts
|
|
964
|
-
*import { continueAsNew } from '@temporalio/workflow';
|
|
965
|
-
import { SearchAttributeType } from '@temporalio/common';
|
|
1048
|
+
* import { continueAsNew } from '@temporalio/workflow';
|
|
1049
|
+
* import { SearchAttributeType } from '@temporalio/common';
|
|
966
1050
|
*
|
|
967
|
-
*export async function myWorkflow(n: number): Promise<void> {
|
|
968
|
-
*
|
|
969
|
-
*
|
|
970
|
-
*}
|
|
1051
|
+
* export async function myWorkflow(n: number): Promise<void> {
|
|
1052
|
+
* // ... Workflow logic
|
|
1053
|
+
* await continueAsNew<typeof myWorkflow>(n + 1);
|
|
1054
|
+
* }
|
|
971
1055
|
* ```
|
|
972
1056
|
*/
|
|
973
1057
|
export function continueAsNew<F extends Workflow>(...args: Parameters<F>): Promise<never> {
|
|
@@ -1049,6 +1133,18 @@ export function deprecatePatch(patchId: string): void {
|
|
|
1049
1133
|
activator.patchInternal(patchId, true);
|
|
1050
1134
|
}
|
|
1051
1135
|
|
|
1136
|
+
/**
|
|
1137
|
+
* Returns a Promise that resolves when `fn` evaluates to `true` or `timeout` expires, providing
|
|
1138
|
+
* options to configure the timer (i.e. provide metadata)
|
|
1139
|
+
*
|
|
1140
|
+
* @param timeout number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
|
|
1141
|
+
*
|
|
1142
|
+
* @returns a boolean indicating whether the condition was true before the timeout expires
|
|
1143
|
+
*
|
|
1144
|
+
* @experimental TimerOptions is a new addition and subject to change
|
|
1145
|
+
*/
|
|
1146
|
+
export function condition(fn: () => boolean, timeout: Duration, options: TimerOptions): Promise<boolean>;
|
|
1147
|
+
|
|
1052
1148
|
/**
|
|
1053
1149
|
* Returns a Promise that resolves when `fn` evaluates to `true` or `timeout` expires.
|
|
1054
1150
|
*
|
|
@@ -1063,7 +1159,7 @@ export function condition(fn: () => boolean, timeout: Duration): Promise<boolean
|
|
|
1063
1159
|
*/
|
|
1064
1160
|
export function condition(fn: () => boolean): Promise<void>;
|
|
1065
1161
|
|
|
1066
|
-
export async function condition(fn: () => boolean, timeout?: Duration): Promise<void | boolean> {
|
|
1162
|
+
export async function condition(fn: () => boolean, timeout?: Duration, opts?: TimerOptions): Promise<void | boolean> {
|
|
1067
1163
|
assertInWorkflowContext('Workflow.condition(...) may only be used from a Workflow Execution.');
|
|
1068
1164
|
// Prior to 1.5.0, `condition(fn, 0)` was treated as equivalent to `condition(fn, undefined)`
|
|
1069
1165
|
if (timeout === 0 && !patched(CONDITION_0_PATCH)) {
|
|
@@ -1072,7 +1168,7 @@ export async function condition(fn: () => boolean, timeout?: Duration): Promise<
|
|
|
1072
1168
|
if (typeof timeout === 'number' || typeof timeout === 'string') {
|
|
1073
1169
|
return CancellationScope.cancellable(async () => {
|
|
1074
1170
|
try {
|
|
1075
|
-
return await Promise.race([sleep(timeout).then(() => false), conditionInner(fn).then(() => true)]);
|
|
1171
|
+
return await Promise.race([sleep(timeout, opts).then(() => false), conditionInner(fn).then(() => true)]);
|
|
1076
1172
|
} finally {
|
|
1077
1173
|
CancellationScope.current().cancel();
|
|
1078
1174
|
}
|
|
@@ -1272,6 +1368,8 @@ export function setHandler<
|
|
|
1272
1368
|
options?: QueryHandlerOptions | SignalHandlerOptions | UpdateHandlerOptions<Args>
|
|
1273
1369
|
): void {
|
|
1274
1370
|
const activator = assertInWorkflowContext('Workflow.setHandler(...) may only be used from a Workflow Execution.');
|
|
1371
|
+
// Cannot register handler for reserved names
|
|
1372
|
+
throwIfReservedName(def.type, def.name);
|
|
1275
1373
|
const description = options?.description;
|
|
1276
1374
|
if (def.type === 'update') {
|
|
1277
1375
|
if (typeof handler === 'function') {
|
|
@@ -1655,3 +1753,13 @@ export function setWorkflowOptions<A extends any[], RT>(
|
|
|
1655
1753
|
export const stackTraceQuery = defineQuery<string>('__stack_trace');
|
|
1656
1754
|
export const enhancedStackTraceQuery = defineQuery<EnhancedStackTrace>('__enhanced_stack_trace');
|
|
1657
1755
|
export const workflowMetadataQuery = defineQuery<temporal.api.sdk.v1.IWorkflowMetadata>('__temporal_workflow_metadata');
|
|
1756
|
+
|
|
1757
|
+
export function getCurrentDetails(): string {
|
|
1758
|
+
const activator = assertInWorkflowContext('getCurrentDetails() may only be used from a Workflow Execution.');
|
|
1759
|
+
return activator.currentDetails;
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
export function setCurrentDetails(details: string): void {
|
|
1763
|
+
const activator = assertInWorkflowContext('getCurrentDetails() may only be used from a Workflow Execution.');
|
|
1764
|
+
activator.currentDetails = details;
|
|
1765
|
+
}
|