@temporalio/workflow 1.4.4 → 1.5.1
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 +1 -2
- package/lib/cancellation-scope.js +6 -4
- package/lib/cancellation-scope.js.map +1 -1
- package/lib/errors.d.ts +0 -1
- package/lib/errors.js +1 -3
- package/lib/errors.js.map +1 -1
- package/lib/index.d.ts +4 -3
- package/lib/index.js +1 -3
- package/lib/index.js.map +1 -1
- package/lib/interceptors.d.ts +1 -1
- package/lib/interfaces.d.ts +13 -3
- package/lib/internals.d.ts +81 -72
- package/lib/internals.js +328 -305
- package/lib/internals.js.map +1 -1
- package/lib/stack-helpers.js +1 -1
- package/lib/stack-helpers.js.map +1 -1
- package/lib/worker-interface.d.ts +3 -27
- package/lib/worker-interface.js +57 -100
- package/lib/worker-interface.js.map +1 -1
- package/lib/workflow.js +92 -86
- package/lib/workflow.js.map +1 -1
- package/package.json +4 -4
- package/src/cancellation-scope.ts +7 -5
- package/src/errors.ts +0 -2
- package/src/index.ts +16 -5
- package/src/interceptors.ts +1 -1
- package/src/interfaces.ts +15 -3
- package/src/internals.ts +403 -347
- package/src/stack-helpers.ts +1 -1
- package/src/worker-interface.ts +59 -105
- package/src/workflow.ts +93 -88
package/src/internals.ts
CHANGED
|
@@ -1,29 +1,35 @@
|
|
|
1
|
-
import { defaultFailureConverter, FailureConverter, PayloadConverter } from '@temporalio/common';
|
|
2
1
|
import type { RawSourceMap } from 'source-map';
|
|
3
2
|
import {
|
|
3
|
+
defaultFailureConverter,
|
|
4
|
+
FailureConverter,
|
|
5
|
+
PayloadConverter,
|
|
4
6
|
arrayFromPayloads,
|
|
5
7
|
defaultPayloadConverter,
|
|
6
8
|
ensureTemporalFailure,
|
|
7
9
|
IllegalStateError,
|
|
8
10
|
TemporalFailure,
|
|
9
11
|
Workflow,
|
|
12
|
+
WorkflowExecutionAlreadyStartedError,
|
|
10
13
|
WorkflowQueryType,
|
|
11
14
|
WorkflowSignalType,
|
|
15
|
+
ProtoFailure,
|
|
12
16
|
} from '@temporalio/common';
|
|
13
17
|
import { composeInterceptors } from '@temporalio/common/lib/interceptors';
|
|
14
18
|
import { checkExtends } from '@temporalio/common/lib/type-helpers';
|
|
15
19
|
import type { coresdk } from '@temporalio/proto';
|
|
16
20
|
import { alea, RNG } from './alea';
|
|
17
|
-
import {
|
|
18
|
-
import { DeterminismViolationError, isCancellation
|
|
21
|
+
import { RootCancellationScope } from './cancellation-scope';
|
|
22
|
+
import { DeterminismViolationError, isCancellation } from './errors';
|
|
23
|
+
import { QueryInput, SignalInput, WorkflowExecuteInput, WorkflowInterceptors } from './interceptors';
|
|
19
24
|
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
ContinueAsNew,
|
|
26
|
+
SDKInfo,
|
|
27
|
+
FileSlice,
|
|
28
|
+
EnhancedStackTrace,
|
|
29
|
+
FileLocation,
|
|
30
|
+
WorkflowInfo,
|
|
31
|
+
WorkflowCreateOptionsWithSourceMap,
|
|
32
|
+
} from './interfaces';
|
|
27
33
|
import { SinkCall } from './sinks';
|
|
28
34
|
import { untrackPromise } from './stack-helpers';
|
|
29
35
|
import pkg from './pkg';
|
|
@@ -49,12 +55,9 @@ export interface PromiseStackStore {
|
|
|
49
55
|
promiseToStack: Map<Promise<unknown>, Stack>;
|
|
50
56
|
}
|
|
51
57
|
|
|
52
|
-
export type ResolveFunction<T = any> = (val: T) => any;
|
|
53
|
-
export type RejectFunction<E = any> = (val: E) => any;
|
|
54
|
-
|
|
55
58
|
export interface Completion {
|
|
56
|
-
resolve:
|
|
57
|
-
reject:
|
|
59
|
+
resolve(val: unknown): unknown;
|
|
60
|
+
reject(reason: unknown): unknown;
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
export interface Condition {
|
|
@@ -74,15 +77,278 @@ export type ActivationHandlerFunction<K extends keyof coresdk.workflow_activatio
|
|
|
74
77
|
activation: NonNullable<coresdk.workflow_activation.IWorkflowActivationJob[K]>
|
|
75
78
|
) => void;
|
|
76
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Verifies all activation job handling methods are implemented
|
|
82
|
+
*/
|
|
77
83
|
export type ActivationHandler = {
|
|
78
84
|
[P in keyof coresdk.workflow_activation.IWorkflowActivationJob]: ActivationHandlerFunction<P>;
|
|
79
85
|
};
|
|
80
86
|
|
|
87
|
+
/**
|
|
88
|
+
* SDK Internal Patches are created by the SDK to avoid breaking history when behaviour
|
|
89
|
+
* of existing API need to be modified. This is the patch number supported by the current
|
|
90
|
+
* version of the SDK.
|
|
91
|
+
*
|
|
92
|
+
* History:
|
|
93
|
+
* 1: Fix `condition(..., 0)` is not the same as `condition(..., undefined)`
|
|
94
|
+
*/
|
|
95
|
+
export const LATEST_INTERNAL_PATCH_NUMBER = 1;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Keeps all of the Workflow runtime state like pending completions for activities and timers.
|
|
99
|
+
*
|
|
100
|
+
* Implements handlers for all workflow activation jobs.
|
|
101
|
+
*/
|
|
81
102
|
export class Activator implements ActivationHandler {
|
|
82
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Map of task sequence to a Completion
|
|
105
|
+
*/
|
|
106
|
+
readonly completions = {
|
|
107
|
+
timer: new Map<number, Completion>(),
|
|
108
|
+
activity: new Map<number, Completion>(),
|
|
109
|
+
childWorkflowStart: new Map<number, Completion>(),
|
|
110
|
+
childWorkflowComplete: new Map<number, Completion>(),
|
|
111
|
+
signalWorkflow: new Map<number, Completion>(),
|
|
112
|
+
cancelWorkflow: new Map<number, Completion>(),
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Holds buffered signal calls until a handler is registered
|
|
117
|
+
*/
|
|
118
|
+
readonly bufferedSignals = new Map<string, coresdk.workflow_activation.ISignalWorkflow[]>();
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Holds buffered query calls until a handler is registered.
|
|
122
|
+
*
|
|
123
|
+
* **IMPORTANT** queries are only buffered until workflow is started.
|
|
124
|
+
* This is required because async interceptors might block workflow function invocation
|
|
125
|
+
* which delays query handler registration.
|
|
126
|
+
*/
|
|
127
|
+
protected readonly bufferedQueries = Array<coresdk.workflow_activation.IQueryWorkflow>();
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Mapping of signal name to handler
|
|
131
|
+
*/
|
|
132
|
+
readonly signalHandlers = new Map<string, WorkflowSignalType>();
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Source map file for looking up the source files in response to __enhanced_stack_trace
|
|
136
|
+
*/
|
|
137
|
+
protected readonly sourceMap: RawSourceMap;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Whether or not to send the sources in enhanced stack trace query responses
|
|
141
|
+
*/
|
|
142
|
+
protected readonly showStackTraceSources;
|
|
143
|
+
|
|
144
|
+
protected readonly promiseStackStore: PromiseStackStore = {
|
|
145
|
+
promiseToStack: new Map(),
|
|
146
|
+
childToParent: new Map(),
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
public readonly rootScope = new RootCancellationScope();
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Mapping of query name to handler
|
|
153
|
+
*/
|
|
154
|
+
public readonly queryHandlers = new Map<string, WorkflowQueryType>([
|
|
155
|
+
[
|
|
156
|
+
'__stack_trace',
|
|
157
|
+
() => {
|
|
158
|
+
return this.getStackTraces()
|
|
159
|
+
.map((s) => s.formatted)
|
|
160
|
+
.join('\n\n');
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
[
|
|
164
|
+
'__enhanced_stack_trace',
|
|
165
|
+
(): EnhancedStackTrace => {
|
|
166
|
+
const { sourceMap } = this;
|
|
167
|
+
const sdk: SDKInfo = { name: 'typescript', version: pkg.version };
|
|
168
|
+
const stacks = this.getStackTraces().map(({ structured: locations }) => ({ locations }));
|
|
169
|
+
const sources: Record<string, FileSlice[]> = {};
|
|
170
|
+
if (this.showStackTraceSources) {
|
|
171
|
+
for (const { locations } of stacks) {
|
|
172
|
+
for (const { filePath } of locations) {
|
|
173
|
+
if (!filePath) continue;
|
|
174
|
+
const content = sourceMap?.sourcesContent?.[sourceMap?.sources.indexOf(filePath)];
|
|
175
|
+
if (!content) continue;
|
|
176
|
+
sources[filePath] = [
|
|
177
|
+
{
|
|
178
|
+
content,
|
|
179
|
+
lineOffset: 0,
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return { sdk, stacks, sources };
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
]);
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Loaded in {@link initRuntime}
|
|
192
|
+
*/
|
|
193
|
+
public readonly interceptors: Required<WorkflowInterceptors> = { inbound: [], outbound: [], internals: [] };
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Buffer that stores all generated commands, reset after each activation
|
|
197
|
+
*/
|
|
198
|
+
protected commands: coresdk.workflow_commands.IWorkflowCommand[] = [];
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Stores all {@link condition}s that haven't been unblocked yet
|
|
202
|
+
*/
|
|
203
|
+
public readonly blockedConditions = new Map<number, Condition>();
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Is this Workflow completed?
|
|
207
|
+
*
|
|
208
|
+
* A Workflow will be considered completed if it generates a command that the
|
|
209
|
+
* system considers as a final Workflow command (e.g.
|
|
210
|
+
* completeWorkflowExecution or failWorkflowExecution).
|
|
211
|
+
*/
|
|
212
|
+
public completed = false;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Was this Workflow cancelled?
|
|
216
|
+
*/
|
|
217
|
+
protected cancelled = false;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* This is tracked to allow buffering queries until a workflow function is called.
|
|
221
|
+
* TODO(bergundy): I don't think this makes sense since queries run last in an activation and must be responded to in
|
|
222
|
+
* the same activation.
|
|
223
|
+
*/
|
|
224
|
+
protected workflowFunctionWasCalled = false;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* The next (incremental) sequence to assign when generating completable commands
|
|
228
|
+
*/
|
|
229
|
+
public nextSeqs = {
|
|
230
|
+
timer: 1,
|
|
231
|
+
activity: 1,
|
|
232
|
+
childWorkflow: 1,
|
|
233
|
+
signalWorkflow: 1,
|
|
234
|
+
cancelWorkflow: 1,
|
|
235
|
+
condition: 1,
|
|
236
|
+
// Used internally to keep track of active stack traces
|
|
237
|
+
stack: 1,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* This is set every time the workflow executes an activation
|
|
242
|
+
*/
|
|
243
|
+
now: number;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Reference to the current Workflow, initialized when a Workflow is started
|
|
247
|
+
*/
|
|
248
|
+
public workflow?: Workflow;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Information about the current Workflow
|
|
252
|
+
*/
|
|
253
|
+
public readonly info: WorkflowInfo;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* A deterministic RNG, used by the isolate's overridden Math.random
|
|
257
|
+
*/
|
|
258
|
+
public random: RNG;
|
|
259
|
+
|
|
260
|
+
public payloadConverter: PayloadConverter = defaultPayloadConverter;
|
|
261
|
+
public failureConverter: FailureConverter = defaultFailureConverter;
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Patches we know the status of for this workflow, as in {@link patched}
|
|
265
|
+
*/
|
|
266
|
+
public readonly knownPresentPatches = new Set<string>();
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Patches we sent to core {@link patched}
|
|
270
|
+
*/
|
|
271
|
+
public readonly sentPatches = new Set<string>();
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* SDK Internal Patches are created by the SDK to avoid breaking history when behaviour
|
|
275
|
+
* of existing API need to be modified.
|
|
276
|
+
*/
|
|
277
|
+
public internalPatchNumber = 0;
|
|
278
|
+
|
|
279
|
+
sinkCalls = Array<SinkCall>();
|
|
280
|
+
|
|
281
|
+
constructor({
|
|
282
|
+
info,
|
|
283
|
+
now,
|
|
284
|
+
showStackTraceSources,
|
|
285
|
+
sourceMap,
|
|
286
|
+
randomnessSeed,
|
|
287
|
+
patches,
|
|
288
|
+
}: WorkflowCreateOptionsWithSourceMap) {
|
|
289
|
+
this.info = info;
|
|
290
|
+
this.now = now;
|
|
291
|
+
this.showStackTraceSources = showStackTraceSources;
|
|
292
|
+
this.sourceMap = sourceMap;
|
|
293
|
+
this.random = alea(randomnessSeed);
|
|
294
|
+
|
|
295
|
+
if (info.unsafe.isReplaying) {
|
|
296
|
+
for (const patch of patches) {
|
|
297
|
+
this.knownPresentPatches.add(patch);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
protected getStackTraces(): Stack[] {
|
|
303
|
+
const { childToParent, promiseToStack } = this.promiseStackStore;
|
|
304
|
+
const internalNodes = [...childToParent.values()].reduce((acc, curr) => {
|
|
305
|
+
for (const p of curr) {
|
|
306
|
+
acc.add(p);
|
|
307
|
+
}
|
|
308
|
+
return acc;
|
|
309
|
+
}, new Set());
|
|
310
|
+
const stacks = new Map<string, Stack>();
|
|
311
|
+
for (const child of childToParent.keys()) {
|
|
312
|
+
if (!internalNodes.has(child)) {
|
|
313
|
+
const stack = promiseToStack.get(child);
|
|
314
|
+
if (!stack || !stack.formatted) continue;
|
|
315
|
+
stacks.set(stack.formatted, stack);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
// Not 100% sure where this comes from, just filter it out
|
|
319
|
+
stacks.delete(' at Promise.then (<anonymous>)');
|
|
320
|
+
stacks.delete(' at Promise.then (<anonymous>)\n');
|
|
321
|
+
return [...stacks].map(([_, stack]) => stack);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
getAndResetSinkCalls(): SinkCall[] {
|
|
325
|
+
const { sinkCalls } = this;
|
|
326
|
+
this.sinkCalls = [];
|
|
327
|
+
return sinkCalls;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Buffer a Workflow command to be collected at the end of the current activation.
|
|
332
|
+
*
|
|
333
|
+
* Prevents commands from being added after Workflow completion.
|
|
334
|
+
*/
|
|
335
|
+
pushCommand(cmd: coresdk.workflow_commands.IWorkflowCommand, complete = false): void {
|
|
336
|
+
// Only query responses may be sent after completion
|
|
337
|
+
if (this.completed && !cmd.respondToQuery) return;
|
|
338
|
+
this.commands.push(cmd);
|
|
339
|
+
if (complete) {
|
|
340
|
+
this.completed = true;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
getAndResetCommands(): coresdk.workflow_commands.IWorkflowCommand[] {
|
|
345
|
+
const commands = this.commands;
|
|
346
|
+
this.commands = [];
|
|
347
|
+
return commands;
|
|
348
|
+
}
|
|
83
349
|
|
|
84
350
|
public async startWorkflowNextHandler({ args }: WorkflowExecuteInput): Promise<any> {
|
|
85
|
-
const { workflow } =
|
|
351
|
+
const { workflow } = this;
|
|
86
352
|
if (workflow === undefined) {
|
|
87
353
|
throw new IllegalStateError('Workflow uninitialized');
|
|
88
354
|
}
|
|
@@ -94,7 +360,7 @@ export class Activator implements ActivationHandler {
|
|
|
94
360
|
// Otherwise this Workflow will now be queryable.
|
|
95
361
|
this.workflowFunctionWasCalled = true;
|
|
96
362
|
// Empty the buffer
|
|
97
|
-
const buffer =
|
|
363
|
+
const buffer = this.bufferedQueries.splice(0);
|
|
98
364
|
for (const activation of buffer) {
|
|
99
365
|
this.queryWorkflow(activation);
|
|
100
366
|
}
|
|
@@ -103,32 +369,24 @@ export class Activator implements ActivationHandler {
|
|
|
103
369
|
}
|
|
104
370
|
|
|
105
371
|
public startWorkflow(activation: coresdk.workflow_activation.IStartWorkflow): void {
|
|
106
|
-
const
|
|
107
|
-
if (info === undefined) {
|
|
108
|
-
throw new IllegalStateError('Workflow has not been initialized');
|
|
109
|
-
}
|
|
110
|
-
const execute = composeInterceptors(
|
|
111
|
-
state.interceptors.inbound,
|
|
112
|
-
'execute',
|
|
113
|
-
this.startWorkflowNextHandler.bind(this)
|
|
114
|
-
);
|
|
372
|
+
const execute = composeInterceptors(this.interceptors.inbound, 'execute', this.startWorkflowNextHandler.bind(this));
|
|
115
373
|
untrackPromise(
|
|
116
374
|
execute({
|
|
117
375
|
headers: activation.headers ?? {},
|
|
118
|
-
args: arrayFromPayloads(
|
|
119
|
-
}).then(completeWorkflow, handleWorkflowFailure)
|
|
376
|
+
args: arrayFromPayloads(this.payloadConverter, activation.arguments),
|
|
377
|
+
}).then(this.completeWorkflow.bind(this), this.handleWorkflowFailure.bind(this))
|
|
120
378
|
);
|
|
121
379
|
}
|
|
122
380
|
|
|
123
381
|
public cancelWorkflow(_activation: coresdk.workflow_activation.ICancelWorkflow): void {
|
|
124
|
-
|
|
125
|
-
|
|
382
|
+
this.cancelled = true;
|
|
383
|
+
this.rootScope.cancel();
|
|
126
384
|
}
|
|
127
385
|
|
|
128
386
|
public fireTimer(activation: coresdk.workflow_activation.IFireTimer): void {
|
|
129
387
|
// Timers are a special case where their completion might not be in Workflow state,
|
|
130
388
|
// this is due to immediate timer cancellation that doesn't go wait for Core.
|
|
131
|
-
const completion = maybeConsumeCompletion('timer', getSeq(activation));
|
|
389
|
+
const completion = this.maybeConsumeCompletion('timer', getSeq(activation));
|
|
132
390
|
completion?.resolve(undefined);
|
|
133
391
|
}
|
|
134
392
|
|
|
@@ -136,18 +394,18 @@ export class Activator implements ActivationHandler {
|
|
|
136
394
|
if (!activation.result) {
|
|
137
395
|
throw new TypeError('Got ResolveActivity activation with no result');
|
|
138
396
|
}
|
|
139
|
-
const { resolve, reject } = consumeCompletion('activity', getSeq(activation));
|
|
397
|
+
const { resolve, reject } = this.consumeCompletion('activity', getSeq(activation));
|
|
140
398
|
if (activation.result.completed) {
|
|
141
399
|
const completed = activation.result.completed;
|
|
142
|
-
const result = completed.result ?
|
|
400
|
+
const result = completed.result ? this.payloadConverter.fromPayload(completed.result) : undefined;
|
|
143
401
|
resolve(result);
|
|
144
402
|
} else if (activation.result.failed) {
|
|
145
403
|
const { failure } = activation.result.failed;
|
|
146
|
-
const err = failure ?
|
|
404
|
+
const err = failure ? this.failureToError(failure) : undefined;
|
|
147
405
|
reject(err);
|
|
148
406
|
} else if (activation.result.cancelled) {
|
|
149
407
|
const { failure } = activation.result.cancelled;
|
|
150
|
-
const err = failure ?
|
|
408
|
+
const err = failure ? this.failureToError(failure) : undefined;
|
|
151
409
|
reject(err);
|
|
152
410
|
} else if (activation.result.backoff) {
|
|
153
411
|
reject(new LocalActivityDoBackoff(activation.result.backoff));
|
|
@@ -157,7 +415,7 @@ export class Activator implements ActivationHandler {
|
|
|
157
415
|
public resolveChildWorkflowExecutionStart(
|
|
158
416
|
activation: coresdk.workflow_activation.IResolveChildWorkflowExecutionStart
|
|
159
417
|
): void {
|
|
160
|
-
const { resolve, reject } = consumeCompletion('childWorkflowStart', getSeq(activation));
|
|
418
|
+
const { resolve, reject } = this.consumeCompletion('childWorkflowStart', getSeq(activation));
|
|
161
419
|
if (activation.succeeded) {
|
|
162
420
|
resolve(activation.succeeded.runId);
|
|
163
421
|
} else if (activation.failed) {
|
|
@@ -181,7 +439,7 @@ export class Activator implements ActivationHandler {
|
|
|
181
439
|
if (!activation.cancelled.failure) {
|
|
182
440
|
throw new TypeError('Got no failure in cancelled variant');
|
|
183
441
|
}
|
|
184
|
-
reject(
|
|
442
|
+
reject(this.failureToError(activation.cancelled.failure));
|
|
185
443
|
} else {
|
|
186
444
|
throw new TypeError('Got ResolveChildWorkflowExecutionStart with no status');
|
|
187
445
|
}
|
|
@@ -191,34 +449,36 @@ export class Activator implements ActivationHandler {
|
|
|
191
449
|
if (!activation.result) {
|
|
192
450
|
throw new TypeError('Got ResolveChildWorkflowExecution activation with no result');
|
|
193
451
|
}
|
|
194
|
-
const { resolve, reject } = consumeCompletion('childWorkflowComplete', getSeq(activation));
|
|
452
|
+
const { resolve, reject } = this.consumeCompletion('childWorkflowComplete', getSeq(activation));
|
|
195
453
|
if (activation.result.completed) {
|
|
196
454
|
const completed = activation.result.completed;
|
|
197
|
-
const result = completed.result ?
|
|
455
|
+
const result = completed.result ? this.payloadConverter.fromPayload(completed.result) : undefined;
|
|
198
456
|
resolve(result);
|
|
199
457
|
} else if (activation.result.failed) {
|
|
200
458
|
const { failure } = activation.result.failed;
|
|
201
459
|
if (failure === undefined || failure === null) {
|
|
202
460
|
throw new TypeError('Got failed result with no failure attribute');
|
|
203
461
|
}
|
|
204
|
-
reject(
|
|
462
|
+
reject(this.failureToError(failure));
|
|
205
463
|
} else if (activation.result.cancelled) {
|
|
206
464
|
const { failure } = activation.result.cancelled;
|
|
207
465
|
if (failure === undefined || failure === null) {
|
|
208
466
|
throw new TypeError('Got cancelled result with no failure attribute');
|
|
209
467
|
}
|
|
210
|
-
reject(
|
|
468
|
+
reject(this.failureToError(failure));
|
|
211
469
|
}
|
|
212
470
|
}
|
|
213
471
|
|
|
214
472
|
// Intentionally not made function async so this handler doesn't show up in the stack trace
|
|
215
473
|
protected queryWorkflowNextHandler({ queryName, args }: QueryInput): Promise<unknown> {
|
|
216
|
-
const fn =
|
|
474
|
+
const fn = this.queryHandlers.get(queryName);
|
|
217
475
|
if (fn === undefined) {
|
|
218
|
-
const knownQueryTypes = [...
|
|
476
|
+
const knownQueryTypes = [...this.queryHandlers.keys()].join(' ');
|
|
219
477
|
// Fail the query
|
|
220
|
-
|
|
221
|
-
|
|
478
|
+
return Promise.reject(
|
|
479
|
+
new ReferenceError(
|
|
480
|
+
`Workflow did not register a handler for ${queryName}. Registered queries: [${knownQueryTypes}]`
|
|
481
|
+
)
|
|
222
482
|
);
|
|
223
483
|
}
|
|
224
484
|
try {
|
|
@@ -234,7 +494,7 @@ export class Activator implements ActivationHandler {
|
|
|
234
494
|
|
|
235
495
|
public queryWorkflow(activation: coresdk.workflow_activation.IQueryWorkflow): void {
|
|
236
496
|
if (!this.workflowFunctionWasCalled) {
|
|
237
|
-
|
|
497
|
+
this.bufferedQueries.push(activation);
|
|
238
498
|
return;
|
|
239
499
|
}
|
|
240
500
|
|
|
@@ -244,23 +504,23 @@ export class Activator implements ActivationHandler {
|
|
|
244
504
|
}
|
|
245
505
|
|
|
246
506
|
const execute = composeInterceptors(
|
|
247
|
-
|
|
507
|
+
this.interceptors.inbound,
|
|
248
508
|
'handleQuery',
|
|
249
509
|
this.queryWorkflowNextHandler.bind(this)
|
|
250
510
|
);
|
|
251
511
|
execute({
|
|
252
512
|
queryName: queryType,
|
|
253
|
-
args: arrayFromPayloads(
|
|
513
|
+
args: arrayFromPayloads(this.payloadConverter, activation.arguments),
|
|
254
514
|
queryId,
|
|
255
515
|
headers: headers ?? {},
|
|
256
516
|
}).then(
|
|
257
|
-
(result) => completeQuery(queryId, result),
|
|
258
|
-
(reason) => failQuery(queryId, reason)
|
|
517
|
+
(result) => this.completeQuery(queryId, result),
|
|
518
|
+
(reason) => this.failQuery(queryId, reason)
|
|
259
519
|
);
|
|
260
520
|
}
|
|
261
521
|
|
|
262
522
|
public async signalWorkflowNextHandler({ signalName, args }: SignalInput): Promise<void> {
|
|
263
|
-
const fn =
|
|
523
|
+
const fn = this.signalHandlers.get(signalName);
|
|
264
524
|
if (fn === undefined) {
|
|
265
525
|
throw new IllegalStateError(`No registered signal handler for signal ${signalName}`);
|
|
266
526
|
}
|
|
@@ -273,33 +533,33 @@ export class Activator implements ActivationHandler {
|
|
|
273
533
|
throw new TypeError('Missing activation signalName');
|
|
274
534
|
}
|
|
275
535
|
|
|
276
|
-
const fn =
|
|
536
|
+
const fn = this.signalHandlers.get(signalName);
|
|
277
537
|
if (fn === undefined) {
|
|
278
|
-
let buffer =
|
|
538
|
+
let buffer = this.bufferedSignals.get(signalName);
|
|
279
539
|
if (buffer === undefined) {
|
|
280
540
|
buffer = [];
|
|
281
|
-
|
|
541
|
+
this.bufferedSignals.set(signalName, buffer);
|
|
282
542
|
}
|
|
283
543
|
buffer.push(activation);
|
|
284
544
|
return;
|
|
285
545
|
}
|
|
286
546
|
|
|
287
547
|
const execute = composeInterceptors(
|
|
288
|
-
|
|
548
|
+
this.interceptors.inbound,
|
|
289
549
|
'handleSignal',
|
|
290
550
|
this.signalWorkflowNextHandler.bind(this)
|
|
291
551
|
);
|
|
292
552
|
execute({
|
|
293
|
-
args: arrayFromPayloads(
|
|
553
|
+
args: arrayFromPayloads(this.payloadConverter, activation.input),
|
|
294
554
|
signalName,
|
|
295
555
|
headers: headers ?? {},
|
|
296
|
-
}).catch(handleWorkflowFailure);
|
|
556
|
+
}).catch(this.handleWorkflowFailure.bind(this));
|
|
297
557
|
}
|
|
298
558
|
|
|
299
559
|
public resolveSignalExternalWorkflow(activation: coresdk.workflow_activation.IResolveSignalExternalWorkflow): void {
|
|
300
|
-
const { resolve, reject } = consumeCompletion('signalWorkflow', getSeq(activation));
|
|
560
|
+
const { resolve, reject } = this.consumeCompletion('signalWorkflow', getSeq(activation));
|
|
301
561
|
if (activation.failure) {
|
|
302
|
-
reject(
|
|
562
|
+
reject(this.failureToError(activation.failure));
|
|
303
563
|
} else {
|
|
304
564
|
resolve(undefined);
|
|
305
565
|
}
|
|
@@ -308,9 +568,9 @@ export class Activator implements ActivationHandler {
|
|
|
308
568
|
public resolveRequestCancelExternalWorkflow(
|
|
309
569
|
activation: coresdk.workflow_activation.IResolveRequestCancelExternalWorkflow
|
|
310
570
|
): void {
|
|
311
|
-
const { resolve, reject } = consumeCompletion('cancelWorkflow', getSeq(activation));
|
|
571
|
+
const { resolve, reject } = this.consumeCompletion('cancelWorkflow', getSeq(activation));
|
|
312
572
|
if (activation.failure) {
|
|
313
|
-
reject(
|
|
573
|
+
reject(this.failureToError(activation.failure));
|
|
314
574
|
} else {
|
|
315
575
|
resolve(undefined);
|
|
316
576
|
}
|
|
@@ -320,331 +580,127 @@ export class Activator implements ActivationHandler {
|
|
|
320
580
|
if (!activation.randomnessSeed) {
|
|
321
581
|
throw new TypeError('Expected activation with randomnessSeed attribute');
|
|
322
582
|
}
|
|
323
|
-
|
|
583
|
+
this.random = alea(activation.randomnessSeed.toBytes());
|
|
324
584
|
}
|
|
325
585
|
|
|
326
586
|
public notifyHasPatch(activation: coresdk.workflow_activation.INotifyHasPatch): void {
|
|
327
587
|
if (!activation.patchId) {
|
|
328
588
|
throw new TypeError('Notify has patch missing patch name');
|
|
329
589
|
}
|
|
330
|
-
|
|
590
|
+
if (activation.patchId.startsWith('__sdk_internal_patch_number:')) {
|
|
591
|
+
const internalPatchNumber = parseInt(activation.patchId.substring('__sdk_internal_patch_number:'.length));
|
|
592
|
+
if (internalPatchNumber > LATEST_INTERNAL_PATCH_NUMBER)
|
|
593
|
+
throw new IllegalStateError(
|
|
594
|
+
`Unsupported internal patch number: ${internalPatchNumber} > ${LATEST_INTERNAL_PATCH_NUMBER}`
|
|
595
|
+
);
|
|
596
|
+
if (this.internalPatchNumber < internalPatchNumber) this.internalPatchNumber = internalPatchNumber;
|
|
597
|
+
} else {
|
|
598
|
+
this.knownPresentPatches.add(activation.patchId);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
public checkInternalPatchAtLeast(minimumPatchNumber: number): boolean {
|
|
603
|
+
if (this.internalPatchNumber >= minimumPatchNumber) return true;
|
|
604
|
+
if (!this.info.unsafe.isReplaying) {
|
|
605
|
+
this.internalPatchNumber = minimumPatchNumber;
|
|
606
|
+
this.pushCommand({
|
|
607
|
+
setPatchMarker: { patchId: `__sdk_internal_patch_number:${LATEST_INTERNAL_PATCH_NUMBER}`, deprecated: false },
|
|
608
|
+
});
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
return false;
|
|
331
612
|
}
|
|
332
613
|
|
|
333
614
|
public removeFromCache(): void {
|
|
334
615
|
throw new IllegalStateError('removeFromCache activation job should not reach workflow');
|
|
335
616
|
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
export type WorkflowsImportFunc = () => Promise<Record<string, any>>;
|
|
339
|
-
export type InterceptorsImportFunc = () => Promise<Array<{ interceptors: WorkflowInterceptorsFactory }>>;
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Keeps all of the Workflow runtime state like pending completions for activities and timers and the scope stack.
|
|
343
|
-
*
|
|
344
|
-
* State mutates each time the Workflow is activated.
|
|
345
|
-
*/
|
|
346
|
-
export class State {
|
|
347
|
-
/**
|
|
348
|
-
* Activator executes activation jobs
|
|
349
|
-
*/
|
|
350
|
-
public readonly activator = new Activator();
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Map of task sequence to a Completion
|
|
354
|
-
*/
|
|
355
|
-
public readonly completions = {
|
|
356
|
-
timer: new Map<number, Completion>(),
|
|
357
|
-
activity: new Map<number, Completion>(),
|
|
358
|
-
childWorkflowStart: new Map<number, Completion>(),
|
|
359
|
-
childWorkflowComplete: new Map<number, Completion>(),
|
|
360
|
-
signalWorkflow: new Map<number, Completion>(),
|
|
361
|
-
cancelWorkflow: new Map<number, Completion>(),
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Holds buffered signal calls until a handler is registered
|
|
366
|
-
*/
|
|
367
|
-
public readonly bufferedSignals = new Map<string, coresdk.workflow_activation.ISignalWorkflow[]>();
|
|
368
617
|
|
|
369
618
|
/**
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
* **IMPORTANT** queries are only buffered until workflow is started.
|
|
373
|
-
* This is required because async interceptors might block workflow function invocation
|
|
374
|
-
* which delays query handler registration.
|
|
375
|
-
*/
|
|
376
|
-
public readonly bufferedQueries = Array<coresdk.workflow_activation.IQueryWorkflow>();
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Mapping of signal name to handler
|
|
619
|
+
* Transforms failures into a command to be sent to the server.
|
|
620
|
+
* Used to handle any failure emitted by the Workflow.
|
|
380
621
|
*/
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
public showStackTraceSources = false;
|
|
392
|
-
|
|
393
|
-
protected getStackTraces(): Stack[] {
|
|
394
|
-
const { childToParent, promiseToStack } = (globalThis as any).__TEMPORAL__.promiseStackStore as PromiseStackStore;
|
|
395
|
-
const internalNodes = [...childToParent.values()].reduce((acc, curr) => {
|
|
396
|
-
for (const p of curr) {
|
|
397
|
-
acc.add(p);
|
|
398
|
-
}
|
|
399
|
-
return acc;
|
|
400
|
-
}, new Set());
|
|
401
|
-
const stacks = new Map<string, Stack>();
|
|
402
|
-
for (const child of childToParent.keys()) {
|
|
403
|
-
if (!internalNodes.has(child)) {
|
|
404
|
-
const stack = promiseToStack.get(child);
|
|
405
|
-
if (!stack || !stack.formatted) continue;
|
|
406
|
-
stacks.set(stack.formatted, stack);
|
|
622
|
+
async handleWorkflowFailure(error: unknown): Promise<void> {
|
|
623
|
+
if (this.cancelled && isCancellation(error)) {
|
|
624
|
+
this.pushCommand({ cancelWorkflowExecution: {} }, true);
|
|
625
|
+
} else if (error instanceof ContinueAsNew) {
|
|
626
|
+
this.pushCommand({ continueAsNewWorkflowExecution: error.command }, true);
|
|
627
|
+
} else {
|
|
628
|
+
if (!(error instanceof TemporalFailure)) {
|
|
629
|
+
// This results in an unhandled rejection which will fail the activation
|
|
630
|
+
// preventing it from completing.
|
|
631
|
+
throw error;
|
|
407
632
|
}
|
|
408
|
-
}
|
|
409
|
-
// Not 100% sure where this comes from, just filter it out
|
|
410
|
-
stacks.delete(' at Promise.then (<anonymous>)');
|
|
411
|
-
stacks.delete(' at Promise.then (<anonymous>)\n');
|
|
412
|
-
return [...stacks].map(([_, stack]) => stack);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* Mapping of query name to handler
|
|
417
|
-
*/
|
|
418
|
-
public readonly queryHandlers = new Map<string, WorkflowQueryType>([
|
|
419
|
-
[
|
|
420
|
-
'__stack_trace',
|
|
421
|
-
() => {
|
|
422
|
-
return this.getStackTraces()
|
|
423
|
-
.map((s) => s.formatted)
|
|
424
|
-
.join('\n\n');
|
|
425
|
-
},
|
|
426
|
-
],
|
|
427
|
-
[
|
|
428
|
-
'__enhanced_stack_trace',
|
|
429
|
-
(): EnhancedStackTrace => {
|
|
430
|
-
const { sourceMap } = this;
|
|
431
|
-
const sdk: SDKInfo = { name: 'typescript', version: pkg.version };
|
|
432
|
-
const stacks = this.getStackTraces().map(({ structured: locations }) => ({ locations }));
|
|
433
|
-
const sources: Record<string, FileSlice[]> = {};
|
|
434
|
-
if (this.showStackTraceSources) {
|
|
435
|
-
for (const { locations } of stacks) {
|
|
436
|
-
for (const { filePath } of locations) {
|
|
437
|
-
if (!filePath) continue;
|
|
438
|
-
const content = sourceMap?.sourcesContent?.[sourceMap?.sources.indexOf(filePath)];
|
|
439
|
-
if (!content) continue;
|
|
440
|
-
sources[filePath] = [
|
|
441
|
-
{
|
|
442
|
-
content,
|
|
443
|
-
lineOffset: 0,
|
|
444
|
-
},
|
|
445
|
-
];
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
return { sdk, stacks, sources };
|
|
450
|
-
},
|
|
451
|
-
],
|
|
452
|
-
]);
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Loaded in {@link initRuntime}
|
|
456
|
-
*/
|
|
457
|
-
public interceptors: Required<WorkflowInterceptors> = { inbound: [], outbound: [], internals: [] };
|
|
458
633
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
public blockedConditions = new Map<number, Condition>();
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Is this Workflow completed?
|
|
471
|
-
*
|
|
472
|
-
* A Workflow will be considered completed if it generates a command that the
|
|
473
|
-
* system considers as a final Workflow command (e.g.
|
|
474
|
-
* completeWorkflowExecution or failWorkflowExecution).
|
|
475
|
-
*/
|
|
476
|
-
public completed = false;
|
|
477
|
-
|
|
478
|
-
/**
|
|
479
|
-
* Was this Workflow cancelled?
|
|
480
|
-
*/
|
|
481
|
-
public cancelled = false;
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* The next (incremental) sequence to assign when generating completable commands
|
|
485
|
-
*/
|
|
486
|
-
public nextSeqs = {
|
|
487
|
-
timer: 1,
|
|
488
|
-
activity: 1,
|
|
489
|
-
childWorkflow: 1,
|
|
490
|
-
signalWorkflow: 1,
|
|
491
|
-
cancelWorkflow: 1,
|
|
492
|
-
condition: 1,
|
|
493
|
-
// Used internally to keep track of active stack traces
|
|
494
|
-
stack: 1,
|
|
495
|
-
};
|
|
496
|
-
|
|
497
|
-
/**
|
|
498
|
-
* This is set every time the workflow executes an activation
|
|
499
|
-
*/
|
|
500
|
-
#now: number | undefined;
|
|
501
|
-
|
|
502
|
-
get now(): number {
|
|
503
|
-
if (this.#now === undefined) {
|
|
504
|
-
throw new IllegalStateError('Tried to get Date before Workflow has been initialized');
|
|
634
|
+
this.pushCommand(
|
|
635
|
+
{
|
|
636
|
+
failWorkflowExecution: {
|
|
637
|
+
failure: this.errorToFailure(error),
|
|
638
|
+
},
|
|
639
|
+
},
|
|
640
|
+
true
|
|
641
|
+
);
|
|
505
642
|
}
|
|
506
|
-
return this.#now;
|
|
507
643
|
}
|
|
508
644
|
|
|
509
|
-
|
|
510
|
-
this
|
|
645
|
+
private completeQuery(queryId: string, result: unknown): void {
|
|
646
|
+
this.pushCommand({
|
|
647
|
+
respondToQuery: { queryId, succeeded: { response: this.payloadConverter.toPayload(result) } },
|
|
648
|
+
});
|
|
511
649
|
}
|
|
512
650
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
*/
|
|
521
|
-
public info?: WorkflowInfo;
|
|
522
|
-
|
|
523
|
-
/**
|
|
524
|
-
* A deterministic RNG, used by the isolate's overridden Math.random
|
|
525
|
-
*/
|
|
526
|
-
public random: RNG = function () {
|
|
527
|
-
throw new IllegalStateError('Tried to use Math.random before Workflow has been initialized');
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
/**
|
|
531
|
-
* Used to import the user workflows
|
|
532
|
-
*
|
|
533
|
-
* Injected on isolate context startup
|
|
534
|
-
*/
|
|
535
|
-
public importWorkflows?: WorkflowsImportFunc;
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Used to import the user interceptors
|
|
539
|
-
*
|
|
540
|
-
* Injected on isolate context startup
|
|
541
|
-
*/
|
|
542
|
-
public importInterceptors?: InterceptorsImportFunc;
|
|
543
|
-
|
|
544
|
-
public payloadConverter: PayloadConverter = defaultPayloadConverter;
|
|
545
|
-
public failureConverter: FailureConverter = defaultFailureConverter;
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
* Patches we know the status of for this workflow, as in {@link patched}
|
|
549
|
-
*/
|
|
550
|
-
public readonly knownPresentPatches = new Set<string>();
|
|
551
|
-
|
|
552
|
-
/**
|
|
553
|
-
* Patches we sent to core {@link patched}
|
|
554
|
-
*/
|
|
555
|
-
public readonly sentPatches = new Set<string>();
|
|
556
|
-
|
|
557
|
-
sinkCalls = Array<SinkCall>();
|
|
558
|
-
|
|
559
|
-
getAndResetSinkCalls(): SinkCall[] {
|
|
560
|
-
const { sinkCalls } = this;
|
|
561
|
-
this.sinkCalls = [];
|
|
562
|
-
return sinkCalls;
|
|
651
|
+
private failQuery(queryId: string, error: unknown): void {
|
|
652
|
+
this.pushCommand({
|
|
653
|
+
respondToQuery: {
|
|
654
|
+
queryId,
|
|
655
|
+
failed: this.errorToFailure(ensureTemporalFailure(error)),
|
|
656
|
+
},
|
|
657
|
+
});
|
|
563
658
|
}
|
|
564
659
|
|
|
565
|
-
/**
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
pushCommand(cmd: coresdk.workflow_commands.IWorkflowCommand, complete = false): void {
|
|
571
|
-
// Only query responses may be sent after completion
|
|
572
|
-
if (this.completed && !cmd.respondToQuery) return;
|
|
573
|
-
this.commands.push(cmd);
|
|
574
|
-
if (complete) {
|
|
575
|
-
this.completed = true;
|
|
660
|
+
/** Consume a completion if it exists in Workflow state */
|
|
661
|
+
private maybeConsumeCompletion(type: keyof Activator['completions'], taskSeq: number): Completion | undefined {
|
|
662
|
+
const completion = this.completions[type].get(taskSeq);
|
|
663
|
+
if (completion !== undefined) {
|
|
664
|
+
this.completions[type].delete(taskSeq);
|
|
576
665
|
}
|
|
666
|
+
return completion;
|
|
577
667
|
}
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
export const state = new State();
|
|
581
668
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
},
|
|
588
|
-
},
|
|
589
|
-
true
|
|
590
|
-
);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* Transforms failures into a command to be sent to the server.
|
|
595
|
-
* Used to handle any failure emitted by the Workflow.
|
|
596
|
-
*/
|
|
597
|
-
export async function handleWorkflowFailure(error: unknown): Promise<void> {
|
|
598
|
-
if (state.cancelled && isCancellation(error)) {
|
|
599
|
-
state.pushCommand({ cancelWorkflowExecution: {} }, true);
|
|
600
|
-
} else if (error instanceof ContinueAsNew) {
|
|
601
|
-
state.pushCommand({ continueAsNewWorkflowExecution: error.command }, true);
|
|
602
|
-
} else {
|
|
603
|
-
if (!(error instanceof TemporalFailure)) {
|
|
604
|
-
// This results in an unhandled rejection which will fail the activation
|
|
605
|
-
// preventing it from completing.
|
|
606
|
-
throw error;
|
|
669
|
+
/** Consume a completion if it exists in Workflow state, throws if it doesn't */
|
|
670
|
+
private consumeCompletion(type: keyof Activator['completions'], taskSeq: number): Completion {
|
|
671
|
+
const completion = this.maybeConsumeCompletion(type, taskSeq);
|
|
672
|
+
if (completion === undefined) {
|
|
673
|
+
throw new IllegalStateError(`No completion for taskSeq ${taskSeq}`);
|
|
607
674
|
}
|
|
675
|
+
return completion;
|
|
676
|
+
}
|
|
608
677
|
|
|
609
|
-
|
|
678
|
+
private completeWorkflow(result: unknown): void {
|
|
679
|
+
this.pushCommand(
|
|
610
680
|
{
|
|
611
|
-
|
|
612
|
-
|
|
681
|
+
completeWorkflowExecution: {
|
|
682
|
+
result: this.payloadConverter.toPayload(result),
|
|
613
683
|
},
|
|
614
684
|
},
|
|
615
685
|
true
|
|
616
686
|
);
|
|
617
687
|
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
function completeQuery(queryId: string, result: unknown) {
|
|
621
|
-
state.pushCommand({
|
|
622
|
-
respondToQuery: { queryId, succeeded: { response: state.payloadConverter.toPayload(result) } },
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
688
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
});
|
|
630
|
-
}
|
|
689
|
+
errorToFailure(err: unknown): ProtoFailure {
|
|
690
|
+
return this.failureConverter.errorToFailure(err, this.payloadConverter);
|
|
691
|
+
}
|
|
631
692
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
const completion = state.completions[type].get(taskSeq);
|
|
635
|
-
if (completion !== undefined) {
|
|
636
|
-
state.completions[type].delete(taskSeq);
|
|
693
|
+
failureToError(failure: ProtoFailure): Error {
|
|
694
|
+
return this.failureConverter.failureToError(failure, this.payloadConverter);
|
|
637
695
|
}
|
|
638
|
-
return completion;
|
|
639
696
|
}
|
|
640
697
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
throw new IllegalStateError(`No completion for taskSeq ${taskSeq}`);
|
|
698
|
+
export function getActivator(): Activator {
|
|
699
|
+
const activator = (globalThis as any).__TEMPORAL__?.activator;
|
|
700
|
+
if (activator === undefined) {
|
|
701
|
+
throw new IllegalStateError('Workflow uninitialized');
|
|
646
702
|
}
|
|
647
|
-
return
|
|
703
|
+
return activator;
|
|
648
704
|
}
|
|
649
705
|
|
|
650
706
|
function getSeq<T extends { seq?: number | null }>(activation: T): number {
|