@temporalio/workflow 1.14.2-canary-release-testing.0 → 1.16.0
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/cancellation-scope.d.ts +2 -2
- package/lib/cancellation-scope.js +2 -2
- package/lib/flags.js +1 -1
- package/lib/flags.js.map +1 -1
- package/lib/global-attributes.d.ts +1 -0
- package/lib/global-attributes.js.map +1 -1
- package/lib/global-overrides.js +6 -6
- package/lib/global-overrides.js.map +1 -1
- package/lib/index.d.ts +43 -10
- package/lib/index.js +42 -8
- package/lib/index.js.map +1 -1
- package/lib/interceptors.d.ts +30 -1
- package/lib/interfaces.d.ts +96 -31
- package/lib/interfaces.js +54 -14
- package/lib/interfaces.js.map +1 -1
- package/lib/internals.d.ts +2 -1
- package/lib/internals.js +24 -7
- package/lib/internals.js.map +1 -1
- package/lib/metrics.js +4 -0
- package/lib/metrics.js.map +1 -1
- package/lib/nexus.d.ts +55 -4
- package/lib/nexus.js +74 -12
- package/lib/nexus.js.map +1 -1
- package/lib/trigger.d.ts +17 -2
- package/lib/trigger.js +17 -2
- package/lib/trigger.js.map +1 -1
- package/lib/workflow.js +18 -13
- package/lib/workflow.js.map +1 -1
- package/package.json +5 -5
- package/src/cancellation-scope.ts +2 -2
- package/src/flags.ts +1 -1
- package/src/global-attributes.ts +4 -3
- package/src/global-overrides.ts +6 -6
- package/src/index.ts +50 -12
- package/src/interceptors.ts +34 -1
- package/src/interfaces.ts +110 -38
- package/src/internals.ts +28 -8
- package/src/metrics.ts +7 -0
- package/src/nexus.ts +94 -14
- package/src/trigger.ts +17 -2
- package/src/workflow.ts +19 -13
package/src/interfaces.ts
CHANGED
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
Priority,
|
|
15
15
|
WorkerDeploymentVersion,
|
|
16
16
|
VersioningBehavior,
|
|
17
|
+
InitialVersioningBehavior,
|
|
18
|
+
SuggestContinueAsNewReason,
|
|
17
19
|
} from '@temporalio/common';
|
|
18
20
|
import { SymbolBasedInstanceOfError } from '@temporalio/common/lib/type-helpers';
|
|
19
21
|
import { makeProtoEnumConverters } from '@temporalio/common/lib/internal-workflow/enums-helpers';
|
|
@@ -45,7 +47,7 @@ export interface WorkflowInfo {
|
|
|
45
47
|
* This value may change during the lifetime of an Execution.
|
|
46
48
|
* @deprecated Use {@link typedSearchAttributes} instead.
|
|
47
49
|
*/
|
|
48
|
-
readonly searchAttributes: SearchAttributes; // eslint-disable-line
|
|
50
|
+
readonly searchAttributes: SearchAttributes; // eslint-disable-line @typescript-eslint/no-deprecated
|
|
49
51
|
|
|
50
52
|
/**
|
|
51
53
|
* Indexed information attached to the Workflow Execution, exposed through an interface.
|
|
@@ -122,6 +124,24 @@ export interface WorkflowInfo {
|
|
|
122
124
|
*/
|
|
123
125
|
readonly continueAsNewSuggested: boolean;
|
|
124
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Whether the workflow's Target Worker Deployment Version has changed from its Pinned Version.
|
|
129
|
+
* When true, the workflow should consider continuing-as-new with
|
|
130
|
+
* `initialVersioningBehavior: 'AUTO_UPGRADE'` to move to the new version.
|
|
131
|
+
*
|
|
132
|
+
* This value changes during the lifetime of an Execution.
|
|
133
|
+
*
|
|
134
|
+
* @experimental Upgrade-on-Continue-as-New is experimental and may change.
|
|
135
|
+
*/
|
|
136
|
+
readonly targetWorkerDeploymentVersionChanged: boolean;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Reason(s) why continue as new is suggested. Can potentially be multiple reasons.
|
|
140
|
+
*
|
|
141
|
+
* @experimental May be removed or changed in the future.
|
|
142
|
+
*/
|
|
143
|
+
readonly suggestedContinueAsNewReasons?: SuggestContinueAsNewReason[];
|
|
144
|
+
|
|
125
145
|
/**
|
|
126
146
|
* Task queue this Workflow is executing on
|
|
127
147
|
*/
|
|
@@ -208,8 +228,6 @@ export interface WorkflowInfo {
|
|
|
208
228
|
* executing this task for the first time and has a Deployment Version set, then its ID will be
|
|
209
229
|
* used. This value may change over the lifetime of the workflow run, but is deterministic and
|
|
210
230
|
* safe to use for branching.
|
|
211
|
-
*
|
|
212
|
-
* @experimental Deployment based versioning is experimental and may change in the future.
|
|
213
231
|
*/
|
|
214
232
|
readonly currentDeploymentVersion?: WorkerDeploymentVersion;
|
|
215
233
|
|
|
@@ -235,7 +253,22 @@ export interface UnsafeWorkflowInfo {
|
|
|
235
253
|
*/
|
|
236
254
|
readonly now: () => number;
|
|
237
255
|
|
|
256
|
+
/**
|
|
257
|
+
* Whether the workflow is currently replaying.
|
|
258
|
+
*/
|
|
238
259
|
readonly isReplaying: boolean;
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Whether the workflow is currently replaying history events.
|
|
263
|
+
*
|
|
264
|
+
* This is similar to {@link isReplaying}, but returns `false` during query handlers and update
|
|
265
|
+
* validators, which are live read-only operations that should not be considered as replaying
|
|
266
|
+
* history events.
|
|
267
|
+
*
|
|
268
|
+
* When this property is true, workflow log messages are suppressed and sinks defined with
|
|
269
|
+
* callDuringReplay=false won't get processed.
|
|
270
|
+
*/
|
|
271
|
+
readonly isReplayingHistoryEvents: boolean;
|
|
239
272
|
}
|
|
240
273
|
|
|
241
274
|
/**
|
|
@@ -304,7 +337,7 @@ export interface ContinueAsNewOptions {
|
|
|
304
337
|
* Searchable attributes to attach to next Workflow run
|
|
305
338
|
* @deprecated Use {@link typedSearchAttributes} instead.
|
|
306
339
|
*/
|
|
307
|
-
searchAttributes?: SearchAttributes; // eslint-disable-line
|
|
340
|
+
searchAttributes?: SearchAttributes; // eslint-disable-line @typescript-eslint/no-deprecated
|
|
308
341
|
/**
|
|
309
342
|
* Specifies additional indexed information to attach to the Workflow Execution. More info:
|
|
310
343
|
* https://docs.temporal.io/docs/typescript/search-attributes
|
|
@@ -322,48 +355,80 @@ export interface ContinueAsNewOptions {
|
|
|
322
355
|
*
|
|
323
356
|
* @default 'COMPATIBLE'
|
|
324
357
|
*
|
|
325
|
-
* @deprecated
|
|
326
|
-
* @experimental The Worker Versioning API is still being designed. Major changes are expected.
|
|
358
|
+
* @deprecated Worker Versioning is now deprecated. Please use the Worker Deployment API instead: https://docs.temporal.io/worker-deployments
|
|
327
359
|
*/
|
|
328
|
-
versioningIntent?: VersioningIntent; // eslint-disable-line
|
|
360
|
+
versioningIntent?: VersioningIntent; // eslint-disable-line @typescript-eslint/no-deprecated
|
|
361
|
+
/**
|
|
362
|
+
* Defines the versioning behavior to be used by the first task of a new workflow run in a continue-as-new chain.
|
|
363
|
+
*
|
|
364
|
+
* @experimental Versioning semantics with continue-as-new are experimental and may change in the future.
|
|
365
|
+
*/
|
|
366
|
+
initialVersioningBehavior?: InitialVersioningBehavior;
|
|
329
367
|
}
|
|
330
368
|
|
|
331
369
|
/**
|
|
332
|
-
*
|
|
333
|
-
* - whether cancellation requests
|
|
334
|
-
* - whether and when
|
|
335
|
-
* {@link ChildWorkflowHandle.result}
|
|
370
|
+
* Determines:
|
|
371
|
+
* - whether cancellation requests should be propagated from the Parent Workflow to the Child, and
|
|
372
|
+
* - whether and when should the Child's cancellation be reported back to the Parent Workflow
|
|
373
|
+
* (i.e. at which moment should the {@link executeChild}'s or {@link ChildWorkflowHandle.result}'s
|
|
374
|
+
* promise fail with a `ChildWorkflowFailure`, with `cause` set to a `CancelledFailure`).
|
|
375
|
+
*
|
|
376
|
+
* Note that this setting only applies to cancellation originating from an external request for the
|
|
377
|
+
* Parent Workflow itself, or from internal cancellation of the `CancellationScope` in which the
|
|
378
|
+
* Child Workflow call was made. Eventual Cancellation of a Child Workflow on completion of the
|
|
379
|
+
* Parent Workflow is controlled by the {@link ParentClosePolicy} setting.
|
|
336
380
|
*
|
|
337
|
-
* @default
|
|
381
|
+
* @default ChildWorkflowCancellationType.WAIT_CANCELLATION_COMPLETED
|
|
338
382
|
*/
|
|
339
|
-
|
|
340
|
-
(typeof ChildWorkflowCancellationType)[keyof typeof ChildWorkflowCancellationType];
|
|
383
|
+
// MAINTENANCE: Keep this typedoc in sync with the `ChildWorkflowOptions.cancellationType` field
|
|
341
384
|
export const ChildWorkflowCancellationType = {
|
|
342
385
|
/**
|
|
343
|
-
*
|
|
386
|
+
* Do not propagate cancellation requests to the Child, and immediately report cancellation
|
|
387
|
+
* to the caller.
|
|
344
388
|
*/
|
|
345
389
|
ABANDON: 'ABANDON',
|
|
346
390
|
|
|
347
391
|
/**
|
|
348
|
-
*
|
|
392
|
+
* Propagate cancellation request from the Parent Workflow to the Child, yet _immediately_ report
|
|
393
|
+
* cancellation to the caller, i.e. without waiting for the server to confirm the cancellation
|
|
394
|
+
* request.
|
|
395
|
+
*
|
|
396
|
+
* Note that this cancellation type provides no guarantee, from the Parent-side, that the
|
|
397
|
+
* cancellation request will actually be atomically added to the Child workflow's history.
|
|
398
|
+
* In particular, the Child may complete (either successfully or uncessfully) before the
|
|
399
|
+
* cancellation is delivered, resulting in a situation where the Parent workflow thinks its child
|
|
400
|
+
* was cancelled, but the child actually completed successfully.
|
|
401
|
+
*
|
|
402
|
+
* To guarantee that the Child will eventually be notified of the cancellation request,
|
|
403
|
+
* use {@link WAIT_CANCELLATION_REQUESTED}.
|
|
349
404
|
*/
|
|
350
405
|
TRY_CANCEL: 'TRY_CANCEL',
|
|
351
406
|
|
|
352
407
|
/**
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
* ignore the cancellation request, in which case an error might be thrown with a different cause, or the Child may
|
|
356
|
-
* complete successfully.
|
|
408
|
+
* Propagate cancellation request from the Parent Workflow to the Child, then wait for the server
|
|
409
|
+
* to confirm that the Child Workflow cancellation request was recorded in its history.
|
|
357
410
|
*
|
|
358
|
-
*
|
|
411
|
+
* This cancellation type guarantees that the Child will eventually be notified of the
|
|
412
|
+
* cancellation request (that is, unless the Child terminates inbetween due to unexpected causes).
|
|
359
413
|
*/
|
|
360
|
-
|
|
414
|
+
WAIT_CANCELLATION_REQUESTED: 'WAIT_CANCELLATION_REQUESTED',
|
|
361
415
|
|
|
362
416
|
/**
|
|
363
|
-
*
|
|
417
|
+
* Propagate cancellation request from the Parent Workflow to the Child, then wait for completion
|
|
418
|
+
* of the Child Workflow.
|
|
419
|
+
*
|
|
420
|
+
* The Child may respect cancellation, in which case the Parent's `executeChild` or
|
|
421
|
+
* `ChildWorkflowHandle.result` promise will fail with a `ChildWorkflowFailure`, with `cause`
|
|
422
|
+
* set to a `CancelledFailure`. On the other hand, the Child may ignore the cancellation request,
|
|
423
|
+
* in which case the corresponding promise will either resolve with a result (if Child completed
|
|
424
|
+
* successfully) or reject with a different cause (if Child completed uncessfully).
|
|
425
|
+
*
|
|
426
|
+
* @default
|
|
364
427
|
*/
|
|
365
|
-
|
|
428
|
+
WAIT_CANCELLATION_COMPLETED: 'WAIT_CANCELLATION_COMPLETED',
|
|
366
429
|
} as const;
|
|
430
|
+
export type ChildWorkflowCancellationType =
|
|
431
|
+
(typeof ChildWorkflowCancellationType)[keyof typeof ChildWorkflowCancellationType];
|
|
367
432
|
|
|
368
433
|
// ts-prune-ignore-next
|
|
369
434
|
export const [encodeChildWorkflowCancellationType, decodeChildWorkflowCancellationType] = makeProtoEnumConverters<
|
|
@@ -387,7 +452,6 @@ export const [encodeChildWorkflowCancellationType, decodeChildWorkflowCancellati
|
|
|
387
452
|
*
|
|
388
453
|
* @see {@link https://docs.temporal.io/concepts/what-is-a-parent-close-policy/ | Parent Close Policy}
|
|
389
454
|
*/
|
|
390
|
-
export type ParentClosePolicy = (typeof ParentClosePolicy)[keyof typeof ParentClosePolicy];
|
|
391
455
|
export const ParentClosePolicy = {
|
|
392
456
|
/**
|
|
393
457
|
* When the Parent is Closed, the Child is Terminated.
|
|
@@ -413,29 +477,30 @@ export const ParentClosePolicy = {
|
|
|
413
477
|
*
|
|
414
478
|
* @deprecated Either leave property `undefined`, or set an explicit policy instead.
|
|
415
479
|
*/
|
|
416
|
-
PARENT_CLOSE_POLICY_UNSPECIFIED: undefined,
|
|
480
|
+
PARENT_CLOSE_POLICY_UNSPECIFIED: undefined,
|
|
417
481
|
|
|
418
482
|
/**
|
|
419
483
|
* When the Parent is Closed, the Child is Terminated.
|
|
420
484
|
*
|
|
421
485
|
* @deprecated Use {@link ParentClosePolicy.TERMINATE} instead.
|
|
422
486
|
*/
|
|
423
|
-
PARENT_CLOSE_POLICY_TERMINATE: 'TERMINATE',
|
|
487
|
+
PARENT_CLOSE_POLICY_TERMINATE: 'TERMINATE',
|
|
424
488
|
|
|
425
489
|
/**
|
|
426
490
|
* When the Parent is Closed, nothing is done to the Child.
|
|
427
491
|
*
|
|
428
492
|
* @deprecated Use {@link ParentClosePolicy.ABANDON} instead.
|
|
429
493
|
*/
|
|
430
|
-
PARENT_CLOSE_POLICY_ABANDON: 'ABANDON',
|
|
494
|
+
PARENT_CLOSE_POLICY_ABANDON: 'ABANDON',
|
|
431
495
|
|
|
432
496
|
/**
|
|
433
497
|
* When the Parent is Closed, the Child is Cancelled.
|
|
434
498
|
*
|
|
435
499
|
* @deprecated Use {@link ParentClosePolicy.REQUEST_CANCEL} instead.
|
|
436
500
|
*/
|
|
437
|
-
PARENT_CLOSE_POLICY_REQUEST_CANCEL: 'REQUEST_CANCEL',
|
|
501
|
+
PARENT_CLOSE_POLICY_REQUEST_CANCEL: 'REQUEST_CANCEL',
|
|
438
502
|
} as const;
|
|
503
|
+
export type ParentClosePolicy = (typeof ParentClosePolicy)[keyof typeof ParentClosePolicy];
|
|
439
504
|
|
|
440
505
|
// ts-prune-ignore-next
|
|
441
506
|
export const [encodeParentClosePolicy, decodeParentClosePolicy] = makeProtoEnumConverters<
|
|
@@ -471,19 +536,26 @@ export interface ChildWorkflowOptions extends Omit<CommonWorkflowOptions, 'workf
|
|
|
471
536
|
taskQueue?: string;
|
|
472
537
|
|
|
473
538
|
/**
|
|
474
|
-
*
|
|
475
|
-
* - whether cancellation requests
|
|
476
|
-
* - whether and when
|
|
477
|
-
* {@link ChildWorkflowHandle.result}
|
|
539
|
+
* Determines:
|
|
540
|
+
* - whether cancellation requests should be propagated from the Parent Workflow to the Child, and
|
|
541
|
+
* - whether and when should the Child's cancellation be reported back to the Parent Workflow
|
|
542
|
+
* (i.e. at which moment should the {@link executeChild}'s or {@link ChildWorkflowHandle.result}'s
|
|
543
|
+
* promise fail with a `ChildWorkflowFailure`, with `cause` set to a `CancelledFailure`).
|
|
544
|
+
*
|
|
545
|
+
* Note that this setting only applies to cancellation originating from an external request for the
|
|
546
|
+
* Parent Workflow itself, or from internal cancellation of the `CancellationScope` in which the
|
|
547
|
+
* Child Workflow call was made. Eventual Cancellation of a Child Workflow on completion of the
|
|
548
|
+
* Parent Workflow is controlled by the {@link ParentClosePolicy} setting.
|
|
478
549
|
*
|
|
479
|
-
* @default
|
|
550
|
+
* @default ChildWorkflowCancellationType.WAIT_CANCELLATION_COMPLETED
|
|
480
551
|
*/
|
|
552
|
+
// MAINTENANCE: Keep this typedoc in sync with the `ChildWorkflowCancellationType` enum
|
|
481
553
|
cancellationType?: ChildWorkflowCancellationType;
|
|
482
554
|
|
|
483
555
|
/**
|
|
484
556
|
* Specifies how the Child reacts to the Parent Workflow reaching a Closed state.
|
|
485
557
|
*
|
|
486
|
-
* @default
|
|
558
|
+
* @default ParentClosePolicy.PARENT_CLOSE_POLICY_TERMINATE
|
|
487
559
|
*/
|
|
488
560
|
parentClosePolicy?: ParentClosePolicy;
|
|
489
561
|
|
|
@@ -493,10 +565,9 @@ export interface ChildWorkflowOptions extends Omit<CommonWorkflowOptions, 'workf
|
|
|
493
565
|
*
|
|
494
566
|
* @default 'COMPATIBLE'
|
|
495
567
|
*
|
|
496
|
-
* @deprecated
|
|
497
|
-
* @experimental The Worker Versioning API is still being designed. Major changes are expected.
|
|
568
|
+
* @deprecated Worker Versioning is now deprecated. Please use the Worker Deployment API instead: https://docs.temporal.io/worker-deployments
|
|
498
569
|
*/
|
|
499
|
-
versioningIntent?: VersioningIntent; // eslint-disable-line
|
|
570
|
+
versioningIntent?: VersioningIntent; // eslint-disable-line @typescript-eslint/no-deprecated
|
|
500
571
|
}
|
|
501
572
|
|
|
502
573
|
export type RequiredChildWorkflowOptions = Required<Pick<ChildWorkflowOptions, 'workflowId' | 'cancellationType'>> & {
|
|
@@ -581,6 +652,7 @@ export interface WorkflowCreateOptionsInternal extends WorkflowCreateOptions {
|
|
|
581
652
|
sourceMap: RawSourceMap;
|
|
582
653
|
registeredActivityNames: Set<string>;
|
|
583
654
|
getTimeOfDay(): bigint;
|
|
655
|
+
stackTracesEnabled: boolean;
|
|
584
656
|
}
|
|
585
657
|
|
|
586
658
|
/**
|
package/src/internals.ts
CHANGED
|
@@ -457,6 +457,8 @@ export class Activator implements ActivationHandler {
|
|
|
457
457
|
|
|
458
458
|
public readonly workflowSandboxDestructors: (() => void)[] = [];
|
|
459
459
|
|
|
460
|
+
protected readonly stackTracesEnabled: boolean;
|
|
461
|
+
|
|
460
462
|
constructor({
|
|
461
463
|
info,
|
|
462
464
|
now,
|
|
@@ -465,6 +467,7 @@ export class Activator implements ActivationHandler {
|
|
|
465
467
|
getTimeOfDay,
|
|
466
468
|
randomnessSeed,
|
|
467
469
|
registeredActivityNames,
|
|
470
|
+
stackTracesEnabled,
|
|
468
471
|
}: WorkflowCreateOptionsInternal) {
|
|
469
472
|
this.getTimeOfDay = getTimeOfDay;
|
|
470
473
|
this.info = info;
|
|
@@ -473,6 +476,7 @@ export class Activator implements ActivationHandler {
|
|
|
473
476
|
this.sourceMap = sourceMap;
|
|
474
477
|
this.random = alea(randomnessSeed);
|
|
475
478
|
this.registeredActivityNames = registeredActivityNames;
|
|
479
|
+
this.stackTracesEnabled = stackTracesEnabled;
|
|
476
480
|
}
|
|
477
481
|
|
|
478
482
|
/**
|
|
@@ -483,6 +487,9 @@ export class Activator implements ActivationHandler {
|
|
|
483
487
|
}
|
|
484
488
|
|
|
485
489
|
protected getStackTraces(): Stack[] {
|
|
490
|
+
if (!this.stackTracesEnabled) {
|
|
491
|
+
throw new IllegalStateError('Workflow stack traces are not enabled on this worker');
|
|
492
|
+
}
|
|
486
493
|
const { childToParent, promiseToStack } = this.promiseStackStore;
|
|
487
494
|
const internalNodes = [...childToParent.values()].reduce((acc, curr) => {
|
|
488
495
|
for (const p of curr) {
|
|
@@ -858,12 +865,26 @@ export class Activator implements ActivationHandler {
|
|
|
858
865
|
let input: UpdateInput;
|
|
859
866
|
try {
|
|
860
867
|
if (runValidator && entry.validator) {
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
868
|
+
// Temporarily mark as not replaying history events during validator execution
|
|
869
|
+
// so that logging is permitted. Validators are live read-only operations.
|
|
870
|
+
const wasReplayingHistoryEvents = this.info.unsafe.isReplayingHistoryEvents;
|
|
871
|
+
this.mutateWorkflowInfo((info) => ({
|
|
872
|
+
...info,
|
|
873
|
+
unsafe: { ...info.unsafe, isReplayingHistoryEvents: false },
|
|
874
|
+
}));
|
|
875
|
+
try {
|
|
876
|
+
const validate = composeInterceptors(
|
|
877
|
+
interceptors,
|
|
878
|
+
'validateUpdate',
|
|
879
|
+
this.validateUpdateNextHandler.bind(this, entry.validator)
|
|
880
|
+
);
|
|
881
|
+
validate(makeInput());
|
|
882
|
+
} finally {
|
|
883
|
+
this.mutateWorkflowInfo((info) => ({
|
|
884
|
+
...info,
|
|
885
|
+
unsafe: { ...info.unsafe, isReplayingHistoryEvents: wasReplayingHistoryEvents },
|
|
886
|
+
}));
|
|
887
|
+
}
|
|
867
888
|
}
|
|
868
889
|
input = makeInput();
|
|
869
890
|
} catch (error) {
|
|
@@ -930,7 +951,6 @@ export class Activator implements ActivationHandler {
|
|
|
930
951
|
const update = this.bufferedUpdates.shift();
|
|
931
952
|
if (update) {
|
|
932
953
|
this.rejectUpdate(
|
|
933
|
-
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
934
954
|
update.protocolInstanceId!,
|
|
935
955
|
ApplicationFailure.nonRetryable(`No registered handler for update: ${update.name}`)
|
|
936
956
|
);
|
|
@@ -997,7 +1017,7 @@ export class Activator implements ActivationHandler {
|
|
|
997
1017
|
while (bufferedSignals.length) {
|
|
998
1018
|
if (this.defaultSignalHandler) {
|
|
999
1019
|
// We have a default signal handler, so all signals are dispatchable
|
|
1000
|
-
|
|
1020
|
+
|
|
1001
1021
|
this.signalWorkflow(bufferedSignals.shift()!);
|
|
1002
1022
|
} else {
|
|
1003
1023
|
const foundIndex = bufferedSignals.findIndex((signal) => this.signalHandlers.has(signal.signalName as string));
|
package/src/metrics.ts
CHANGED
|
@@ -48,6 +48,9 @@ class WorkflowMetricMeterImpl implements MetricMeter {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
class WorkflowMetricCounter implements MetricCounter {
|
|
51
|
+
public readonly kind = 'counter';
|
|
52
|
+
public readonly valueType = 'int';
|
|
53
|
+
|
|
51
54
|
constructor(
|
|
52
55
|
public readonly name: string,
|
|
53
56
|
public readonly unit: string | undefined,
|
|
@@ -70,6 +73,8 @@ class WorkflowMetricCounter implements MetricCounter {
|
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
class WorkflowMetricHistogram implements MetricHistogram {
|
|
76
|
+
public readonly kind = 'histogram';
|
|
77
|
+
|
|
73
78
|
constructor(
|
|
74
79
|
public readonly name: string,
|
|
75
80
|
public readonly valueType: NumericMetricValueType,
|
|
@@ -93,6 +98,8 @@ class WorkflowMetricHistogram implements MetricHistogram {
|
|
|
93
98
|
}
|
|
94
99
|
|
|
95
100
|
class WorkflowMetricGauge implements MetricGauge {
|
|
101
|
+
public readonly kind = 'gauge';
|
|
102
|
+
|
|
96
103
|
constructor(
|
|
97
104
|
public readonly name: string,
|
|
98
105
|
public readonly valueType: NumericMetricValueType,
|
package/src/nexus.ts
CHANGED
|
@@ -2,6 +2,8 @@ import * as nexus from 'nexus-rpc';
|
|
|
2
2
|
import { msOptionalToTs } from '@temporalio/common/lib/time';
|
|
3
3
|
import { userMetadataToPayload } from '@temporalio/common/lib/user-metadata';
|
|
4
4
|
import { composeInterceptors } from '@temporalio/common/lib/interceptors';
|
|
5
|
+
import { makeProtoEnumConverters } from '@temporalio/common/lib/internal-workflow/enums-helpers';
|
|
6
|
+
import type { coresdk } from '@temporalio/proto';
|
|
5
7
|
import { CancellationScope } from './cancellation-scope';
|
|
6
8
|
import { getActivator } from './global-attributes';
|
|
7
9
|
import { untrackPromise } from './stack-helpers';
|
|
@@ -12,7 +14,7 @@ import { StartNexusOperationInput, StartNexusOperationOutput, StartNexusOperatio
|
|
|
12
14
|
*
|
|
13
15
|
* @experimental Nexus support in Temporal SDK is experimental.
|
|
14
16
|
*/
|
|
15
|
-
export interface
|
|
17
|
+
export interface NexusServiceClient<T extends nexus.ServiceDefinition> {
|
|
16
18
|
/**
|
|
17
19
|
* Start a Nexus Operation and wait for its completion taking a {@link nexus.operation}.
|
|
18
20
|
* Returns the operation's result.
|
|
@@ -102,9 +104,9 @@ export interface NexusOperationHandle<T> {
|
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
/**
|
|
105
|
-
* Options for {@link
|
|
107
|
+
* Options for {@link createNexusServiceClient}.
|
|
106
108
|
*/
|
|
107
|
-
export interface
|
|
109
|
+
export interface NexusServiceClientOptions<T> {
|
|
108
110
|
endpoint: string;
|
|
109
111
|
service: T;
|
|
110
112
|
}
|
|
@@ -114,8 +116,10 @@ export interface NexusClientOptions<T> {
|
|
|
114
116
|
*
|
|
115
117
|
* @experimental Nexus support in Temporal SDK is experimental.
|
|
116
118
|
*/
|
|
117
|
-
export function
|
|
118
|
-
|
|
119
|
+
export function createNexusServiceClient<T extends nexus.ServiceDefinition>(
|
|
120
|
+
options: NexusServiceClientOptions<T>
|
|
121
|
+
): NexusServiceClient<T> {
|
|
122
|
+
class NexusServiceClientImpl<T extends nexus.ServiceDefinition> implements NexusServiceClient<T> {
|
|
119
123
|
async executeOperation<O extends T['operations'][keyof T['operations']]>(
|
|
120
124
|
operation: string | T['operations'][nexus.OperationKey<T['operations']>],
|
|
121
125
|
input: nexus.OperationInput<T['operations'][nexus.OperationKey<T['operations']>]>,
|
|
@@ -146,17 +150,18 @@ export function createNexusClient<T extends nexus.ServiceDefinition>(options: Ne
|
|
|
146
150
|
startNexusOperationNextHandler
|
|
147
151
|
);
|
|
148
152
|
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
// That's totally different from what we did in ChildWorkflow, but I think that's cleaner from
|
|
154
|
-
// interceptors point of view, and will make it easier to extend the API in the future.
|
|
153
|
+
// The interceptor returns a Promise<StartNexusOperationOutput>, with the result promise contained
|
|
154
|
+
// in that Output object. As a consequence of this, the result promise/completion does not exist
|
|
155
|
+
// until the StartNexusOperation event is received. This is totally different from what we did in
|
|
156
|
+
// ChildWorkflow, but is much cleaner from the interceptors point of view.
|
|
155
157
|
const { token, result: resultPromise } = await execute({
|
|
156
158
|
endpoint: options.endpoint,
|
|
157
159
|
service: options.service.name,
|
|
158
160
|
operation: opName,
|
|
159
|
-
options:
|
|
161
|
+
options: {
|
|
162
|
+
...operationOptions,
|
|
163
|
+
cancellationType: operationOptions?.cancellationType ?? 'WAIT_CANCELLATION_COMPLETED',
|
|
164
|
+
},
|
|
160
165
|
headers: {},
|
|
161
166
|
seq,
|
|
162
167
|
input,
|
|
@@ -173,7 +178,7 @@ export function createNexusClient<T extends nexus.ServiceDefinition>(options: Ne
|
|
|
173
178
|
}
|
|
174
179
|
}
|
|
175
180
|
|
|
176
|
-
return new
|
|
181
|
+
return new NexusServiceClientImpl<T>();
|
|
177
182
|
}
|
|
178
183
|
|
|
179
184
|
function startNexusOperationNextHandler({
|
|
@@ -220,7 +225,9 @@ function startNexusOperationNextHandler({
|
|
|
220
225
|
nexusHeader: headers,
|
|
221
226
|
input: activator.payloadConverter.toPayload(input),
|
|
222
227
|
scheduleToCloseTimeout: msOptionalToTs(options?.scheduleToCloseTimeout),
|
|
223
|
-
|
|
228
|
+
scheduleToStartTimeout: msOptionalToTs(options?.scheduleToStartTimeout),
|
|
229
|
+
startToCloseTimeout: msOptionalToTs(options?.startToCloseTimeout),
|
|
230
|
+
cancellationType: encodeNexusOperationCancellationType(options?.cancellationType),
|
|
224
231
|
},
|
|
225
232
|
userMetadata: userMetadataToPayload(activator.payloadConverter, options?.summary, undefined),
|
|
226
233
|
});
|
|
@@ -231,3 +238,76 @@ function startNexusOperationNextHandler({
|
|
|
231
238
|
});
|
|
232
239
|
});
|
|
233
240
|
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Determines:
|
|
244
|
+
* - whether cancellation requests should be propagated from the Workflow to the Nexus Operation
|
|
245
|
+
* - whether and when should the Operation's cancellation be reported back to the Workflow
|
|
246
|
+
* (i.e. at which moment should the operation's result promise fail with a `NexusOperationFailure`,
|
|
247
|
+
* with `cause` set to a `CancelledFailure`).
|
|
248
|
+
*
|
|
249
|
+
* Note that this setting only applies to cancellation originating from an external request for the
|
|
250
|
+
* Workflow itself, or from internal cancellation of the `CancellationScope` in which the
|
|
251
|
+
* Operation call was made.
|
|
252
|
+
*
|
|
253
|
+
* @experimental Nexus support in Temporal SDK is experimental.
|
|
254
|
+
*/
|
|
255
|
+
// MAINTENANCE: Keep this typedoc in sync with the `StartNexusOperationOptions.cancellationType` field
|
|
256
|
+
export const NexusOperationCancellationType = {
|
|
257
|
+
/**
|
|
258
|
+
* Do not propagate cancellation requests to the Nexus Operation, and immediately report
|
|
259
|
+
* cancellation to the caller.
|
|
260
|
+
*/
|
|
261
|
+
ABANDON: 'ABANDON',
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Initiate a cancellation request for the Nexus operation and immediately report cancellation to
|
|
265
|
+
* the caller. Note that it doesn't guarantee that cancellation is delivered to the operation if
|
|
266
|
+
* calling workflow exits before the delivery is done. If you want to ensure that cancellation is
|
|
267
|
+
* delivered to the operation, use {@link WAIT_CANCELLATION_REQUESTED}.
|
|
268
|
+
*
|
|
269
|
+
* Propagate cancellation request from the Workflow to the Operation, yet _immediately_ report
|
|
270
|
+
* cancellation to the caller, i.e. without waiting for the server to confirm the cancellation
|
|
271
|
+
* request.
|
|
272
|
+
*
|
|
273
|
+
* Note that this cancellation type provides no guarantee, from the Workflow-side, that the
|
|
274
|
+
* cancellation request will be delivered to the Operation Handler. In particular, either the
|
|
275
|
+
* Operation or the Workflow may complete (either successfully or uncessfully) before the
|
|
276
|
+
* cancellation request is delivered, resulting in a situation where the Operation completed
|
|
277
|
+
* successfully, but the Workflow thinks it was cancelled.
|
|
278
|
+
*
|
|
279
|
+
* To guarantee that the Operation will eventually be notified of the cancellation request,
|
|
280
|
+
* use {@link WAIT_CANCELLATION_REQUESTED}.
|
|
281
|
+
*/
|
|
282
|
+
TRY_CANCEL: 'TRY_CANCEL',
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Propagate cancellation request from the Workflow to the Operation, then wait for the server
|
|
286
|
+
* to confirm that the Operation cancellation request was delivered to the Operation Handler.
|
|
287
|
+
*/
|
|
288
|
+
WAIT_CANCELLATION_REQUESTED: 'WAIT_CANCELLATION_REQUESTED',
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Propagate cancellation request from the Workflow to the Operation, then wait for completion
|
|
292
|
+
* of the Operation.
|
|
293
|
+
*/
|
|
294
|
+
WAIT_CANCELLATION_COMPLETED: 'WAIT_CANCELLATION_COMPLETED',
|
|
295
|
+
} as const;
|
|
296
|
+
export type NexusOperationCancellationType =
|
|
297
|
+
(typeof NexusOperationCancellationType)[keyof typeof NexusOperationCancellationType];
|
|
298
|
+
|
|
299
|
+
const [encodeNexusOperationCancellationType, _] = makeProtoEnumConverters<
|
|
300
|
+
coresdk.nexus.NexusOperationCancellationType,
|
|
301
|
+
typeof coresdk.nexus.NexusOperationCancellationType,
|
|
302
|
+
keyof typeof coresdk.nexus.NexusOperationCancellationType,
|
|
303
|
+
typeof NexusOperationCancellationType,
|
|
304
|
+
''
|
|
305
|
+
>(
|
|
306
|
+
{
|
|
307
|
+
[NexusOperationCancellationType.WAIT_CANCELLATION_COMPLETED]: 0,
|
|
308
|
+
[NexusOperationCancellationType.ABANDON]: 1,
|
|
309
|
+
[NexusOperationCancellationType.TRY_CANCEL]: 2,
|
|
310
|
+
[NexusOperationCancellationType.WAIT_CANCELLATION_REQUESTED]: 3,
|
|
311
|
+
} as const,
|
|
312
|
+
''
|
|
313
|
+
);
|
package/src/trigger.ts
CHANGED
|
@@ -10,8 +10,23 @@ import { untrackPromise } from './stack-helpers';
|
|
|
10
10
|
* Useful for e.g. waiting for unblocking a Workflow from a Signal.
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { defineSignal, setHandler, sleep, Trigger } from '@temporalio/workflow';
|
|
15
|
+
*
|
|
16
|
+
* const completeUserInteraction = defineSignal('completeUserInteraction');
|
|
17
|
+
*
|
|
18
|
+
* export async function waitOnUser(userId: string): Promise<void> {
|
|
19
|
+
* const userInteraction = new Trigger<boolean>();
|
|
20
|
+
*
|
|
21
|
+
* // programmatically resolve Trigger
|
|
22
|
+
* setHandler(completeUserInteraction, () => userInteraction.resolve(true));
|
|
23
|
+
*
|
|
24
|
+
* const userInteracted = await Promise.race([userInteraction, sleep('30 days')]);
|
|
25
|
+
* if (!userInteracted) {
|
|
26
|
+
* await sendReminderEmail(userId);
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
15
30
|
*/
|
|
16
31
|
export class Trigger<T> implements PromiseLike<T> {
|
|
17
32
|
// Typescript does not realize that the promise executor is run synchronously in the constructor
|