@temporalio/workflow 1.11.7 → 1.12.0-rc.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/alea.js +5 -3
- package/lib/alea.js.map +1 -1
- package/lib/cancellation-scope.js +36 -18
- package/lib/cancellation-scope.js.map +1 -1
- package/lib/errors.js +1 -0
- package/lib/errors.js.map +1 -1
- package/lib/flags.js +1 -1
- package/lib/flags.js.map +1 -1
- package/lib/index.d.ts +6 -3
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/interceptors.d.ts +11 -1
- package/lib/interfaces.d.ts +68 -5
- package/lib/interfaces.js +1 -0
- package/lib/interfaces.js.map +1 -1
- package/lib/internals.d.ts +55 -5
- package/lib/internals.js +323 -193
- package/lib/internals.js.map +1 -1
- package/lib/logs.js +11 -1
- package/lib/logs.js.map +1 -1
- package/lib/metrics.d.ts +32 -0
- package/lib/metrics.js +118 -0
- package/lib/metrics.js.map +1 -0
- package/lib/trigger.js +8 -0
- package/lib/trigger.js.map +1 -1
- package/lib/update-scope.js +8 -0
- package/lib/update-scope.js.map +1 -1
- package/lib/worker-interface.d.ts +6 -1
- package/lib/worker-interface.js +165 -103
- package/lib/worker-interface.js.map +1 -1
- package/lib/workflow.d.ts +75 -17
- package/lib/workflow.js +204 -31
- package/lib/workflow.js.map +1 -1
- package/package.json +7 -4
- package/src/flags.ts +1 -1
- package/src/index.ts +4 -2
- package/src/interceptors.ts +21 -1
- package/src/interfaces.ts +81 -7
- package/src/internals.ts +133 -23
- package/src/logs.ts +11 -1
- package/src/metrics.ts +191 -0
- package/src/worker-interface.ts +164 -107
- package/src/workflow.ts +229 -35
package/lib/internals.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Activator = void 0;
|
|
7
7
|
const common_1 = require("@temporalio/common");
|
|
8
|
+
const payload_search_attributes_1 = require("@temporalio/common/lib/converter/payload-search-attributes");
|
|
8
9
|
const interceptors_1 = require("@temporalio/common/lib/interceptors");
|
|
9
10
|
const internal_workflow_1 = require("@temporalio/common/lib/internal-workflow");
|
|
10
11
|
const alea_1 = require("./alea");
|
|
@@ -42,186 +43,263 @@ const [_encodeStartChildWorkflowExecutionFailedCause, decodeStartChildWorkflowEx
|
|
|
42
43
|
* - Call user-defined functions, including any form of interceptor.
|
|
43
44
|
*/
|
|
44
45
|
class Activator {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Cache for modules - referenced in reusable-vm.ts
|
|
48
|
+
*/
|
|
49
|
+
moduleCache = new Map();
|
|
50
|
+
/**
|
|
51
|
+
* Map of task sequence to a Completion
|
|
52
|
+
*/
|
|
53
|
+
completions = {
|
|
54
|
+
timer: new Map(),
|
|
55
|
+
activity: new Map(),
|
|
56
|
+
childWorkflowStart: new Map(),
|
|
57
|
+
childWorkflowComplete: new Map(),
|
|
58
|
+
signalWorkflow: new Map(),
|
|
59
|
+
cancelWorkflow: new Map(),
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Holds buffered Update calls until a handler is registered
|
|
63
|
+
*/
|
|
64
|
+
bufferedUpdates = Array();
|
|
65
|
+
/**
|
|
66
|
+
* Holds buffered signal calls until a handler is registered
|
|
67
|
+
*/
|
|
68
|
+
bufferedSignals = Array();
|
|
69
|
+
/**
|
|
70
|
+
* Mapping of update name to handler and validator
|
|
71
|
+
*/
|
|
72
|
+
updateHandlers = new Map();
|
|
73
|
+
/**
|
|
74
|
+
* Mapping of signal name to handler
|
|
75
|
+
*/
|
|
76
|
+
signalHandlers = new Map();
|
|
77
|
+
/**
|
|
78
|
+
* Mapping of in-progress updates to handler execution information.
|
|
79
|
+
*/
|
|
80
|
+
inProgressUpdates = new Map();
|
|
81
|
+
/**
|
|
82
|
+
* Mapping of in-progress signals to handler execution information.
|
|
83
|
+
*/
|
|
84
|
+
inProgressSignals = new Map();
|
|
85
|
+
/**
|
|
86
|
+
* A sequence number providing unique identifiers for signal handler executions.
|
|
87
|
+
*/
|
|
88
|
+
signalHandlerExecutionSeq = 0;
|
|
89
|
+
/**
|
|
90
|
+
* A signal handler that catches calls for non-registered signal names.
|
|
91
|
+
*/
|
|
92
|
+
defaultSignalHandler;
|
|
93
|
+
/**
|
|
94
|
+
* A update handler that catches calls for non-registered update names.
|
|
95
|
+
*/
|
|
96
|
+
defaultUpdateHandler;
|
|
97
|
+
/**
|
|
98
|
+
* A query handler that catches calls for non-registered query names.
|
|
99
|
+
*/
|
|
100
|
+
defaultQueryHandler;
|
|
101
|
+
/**
|
|
102
|
+
* Source map file for looking up the source files in response to __enhanced_stack_trace
|
|
103
|
+
*/
|
|
104
|
+
sourceMap;
|
|
105
|
+
/**
|
|
106
|
+
* Whether or not to send the sources in enhanced stack trace query responses
|
|
107
|
+
*/
|
|
108
|
+
showStackTraceSources;
|
|
109
|
+
promiseStackStore = {
|
|
110
|
+
promiseToStack: new Map(),
|
|
111
|
+
childToParent: new Map(),
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* The error that caused the current Workflow Task to fail. Sets if a non-`TemporalFailure`
|
|
115
|
+
* error bubbles up out of the Workflow function, or out of a Signal or Update handler. We
|
|
116
|
+
* capture errors this way because those functions are not technically awaited when started,
|
|
117
|
+
* but left to run asynchronously. There is therefore no real "parent" function that can
|
|
118
|
+
* directly handle those errors, and not capturing it would result in an Unhandled Promise
|
|
119
|
+
* Rejection. So instead, we buffer the error here, to then be processed in the context
|
|
120
|
+
* of our own synchronous Activation handling event loop.
|
|
121
|
+
*
|
|
122
|
+
* Our code does a best effort to stop processing the current activation as soon as possible
|
|
123
|
+
* after this field is set:
|
|
124
|
+
* - If an error is thrown while executing code synchronously (e.g. anything before the
|
|
125
|
+
* first `await` statement in a Workflow function or a signal/update handler), the error
|
|
126
|
+
* will be _immediately_ rethrown, which will prevent execution of further jobs in the
|
|
127
|
+
* current activation. We know we're currently running code synchronously thanks to the
|
|
128
|
+
* `rethrowSynchronously` flag below.
|
|
129
|
+
* - It an error is thrown while executing microtasks, then the error will be rethrown on
|
|
130
|
+
* the next call to `tryUnblockConditions()`.
|
|
131
|
+
*
|
|
132
|
+
* Unfortunately, there's no way for us to prevent further execution of microtasks that have
|
|
133
|
+
* already been scheduled, nor those that will be recursively scheduled from those microtasks.
|
|
134
|
+
* Should more errors get thrown while settling microtasks, those will be ignored (i.e. only
|
|
135
|
+
* the first captured error is preserved).
|
|
136
|
+
*/
|
|
137
|
+
workflowTaskError;
|
|
138
|
+
/**
|
|
139
|
+
* Set to true when running synchronous code (e.g. while processing activation jobs and when calling
|
|
140
|
+
* `tryUnblockConditions()`). While this flag is set, it is safe to let errors bubble up.
|
|
141
|
+
*/
|
|
142
|
+
rethrowSynchronously = false;
|
|
143
|
+
rootScope = new cancellation_scope_1.RootCancellationScope();
|
|
144
|
+
/**
|
|
145
|
+
* Mapping of query name to handler
|
|
146
|
+
*/
|
|
147
|
+
queryHandlers = new Map([
|
|
148
|
+
[
|
|
149
|
+
'__stack_trace',
|
|
150
|
+
{
|
|
151
|
+
handler: () => {
|
|
152
|
+
return this.getStackTraces()
|
|
153
|
+
.map((s) => s.formatted)
|
|
154
|
+
.join('\n\n');
|
|
107
155
|
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
156
|
+
description: 'Returns a sensible stack trace.',
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
[
|
|
160
|
+
'__enhanced_stack_trace',
|
|
161
|
+
{
|
|
162
|
+
handler: () => {
|
|
163
|
+
const { sourceMap } = this;
|
|
164
|
+
const sdk = { name: 'typescript', version: pkg_1.default.version };
|
|
165
|
+
const stacks = this.getStackTraces().map(({ structured: locations }) => ({ locations }));
|
|
166
|
+
const sources = {};
|
|
167
|
+
if (this.showStackTraceSources) {
|
|
168
|
+
for (const { locations } of stacks) {
|
|
169
|
+
for (const { file_path } of locations) {
|
|
170
|
+
if (!file_path)
|
|
171
|
+
continue;
|
|
172
|
+
const content = sourceMap?.sourcesContent?.[sourceMap?.sources.indexOf(file_path)];
|
|
173
|
+
if (!content)
|
|
174
|
+
continue;
|
|
175
|
+
sources[file_path] = [
|
|
176
|
+
{
|
|
177
|
+
line_offset: 0,
|
|
178
|
+
content,
|
|
179
|
+
},
|
|
180
|
+
];
|
|
132
181
|
}
|
|
133
182
|
}
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
description: 'Returns a stack trace annotated with source information.',
|
|
183
|
+
}
|
|
184
|
+
return { sdk, stacks, sources };
|
|
137
185
|
},
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
186
|
+
description: 'Returns a stack trace annotated with source information.',
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
[
|
|
190
|
+
'__temporal_workflow_metadata',
|
|
191
|
+
{
|
|
192
|
+
handler: () => {
|
|
193
|
+
const workflowType = this.info.workflowType;
|
|
194
|
+
const queryDefinitions = Array.from(this.queryHandlers.entries()).map(([name, value]) => ({
|
|
195
|
+
name,
|
|
196
|
+
description: value.description,
|
|
197
|
+
}));
|
|
198
|
+
const signalDefinitions = Array.from(this.signalHandlers.entries()).map(([name, value]) => ({
|
|
199
|
+
name,
|
|
200
|
+
description: value.description,
|
|
201
|
+
}));
|
|
202
|
+
const updateDefinitions = Array.from(this.updateHandlers.entries()).map(([name, value]) => ({
|
|
203
|
+
name,
|
|
204
|
+
description: value.description,
|
|
205
|
+
}));
|
|
206
|
+
return {
|
|
207
|
+
definition: {
|
|
208
|
+
type: workflowType,
|
|
209
|
+
queryDefinitions,
|
|
210
|
+
signalDefinitions,
|
|
211
|
+
updateDefinitions,
|
|
212
|
+
},
|
|
213
|
+
};
|
|
166
214
|
},
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
215
|
+
description: 'Returns metadata associated with this workflow.',
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
]);
|
|
219
|
+
/**
|
|
220
|
+
* Loaded in {@link initRuntime}
|
|
221
|
+
*/
|
|
222
|
+
interceptors = {
|
|
223
|
+
inbound: [],
|
|
224
|
+
outbound: [],
|
|
225
|
+
internals: [],
|
|
226
|
+
};
|
|
227
|
+
/**
|
|
228
|
+
* Buffer that stores all generated commands, reset after each activation
|
|
229
|
+
*/
|
|
230
|
+
commands = [];
|
|
231
|
+
/**
|
|
232
|
+
* Stores all {@link condition}s that haven't been unblocked yet
|
|
233
|
+
*/
|
|
234
|
+
blockedConditions = new Map();
|
|
235
|
+
/**
|
|
236
|
+
* Is this Workflow completed?
|
|
237
|
+
*
|
|
238
|
+
* A Workflow will be considered completed if it generates a command that the
|
|
239
|
+
* system considers as a final Workflow command (e.g.
|
|
240
|
+
* completeWorkflowExecution or failWorkflowExecution).
|
|
241
|
+
*/
|
|
242
|
+
completed = false;
|
|
243
|
+
/**
|
|
244
|
+
* Was this Workflow cancelled?
|
|
245
|
+
*/
|
|
246
|
+
cancelled = false;
|
|
247
|
+
/**
|
|
248
|
+
* The next (incremental) sequence to assign when generating completable commands
|
|
249
|
+
*/
|
|
250
|
+
nextSeqs = {
|
|
251
|
+
timer: 1,
|
|
252
|
+
activity: 1,
|
|
253
|
+
childWorkflow: 1,
|
|
254
|
+
signalWorkflow: 1,
|
|
255
|
+
cancelWorkflow: 1,
|
|
256
|
+
condition: 1,
|
|
257
|
+
// Used internally to keep track of active stack traces
|
|
258
|
+
stack: 1,
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* This is set every time the workflow executes an activation
|
|
262
|
+
* May be accessed and modified from outside the VM.
|
|
263
|
+
*/
|
|
264
|
+
now;
|
|
265
|
+
/**
|
|
266
|
+
* Reference to the current Workflow, initialized when a Workflow is started
|
|
267
|
+
*/
|
|
268
|
+
workflow;
|
|
269
|
+
/**
|
|
270
|
+
* Information about the current Workflow
|
|
271
|
+
* May be accessed from outside the VM.
|
|
272
|
+
*/
|
|
273
|
+
info;
|
|
274
|
+
/**
|
|
275
|
+
* A deterministic RNG, used by the isolate's overridden Math.random
|
|
276
|
+
*/
|
|
277
|
+
random;
|
|
278
|
+
payloadConverter = common_1.defaultPayloadConverter;
|
|
279
|
+
failureConverter = common_1.defaultFailureConverter;
|
|
280
|
+
/**
|
|
281
|
+
* Patches we know the status of for this workflow, as in {@link patched}
|
|
282
|
+
*/
|
|
283
|
+
knownPresentPatches = new Set();
|
|
284
|
+
/**
|
|
285
|
+
* Patches we sent to core {@link patched}
|
|
286
|
+
*/
|
|
287
|
+
sentPatches = new Set();
|
|
288
|
+
knownFlags = new Set();
|
|
289
|
+
/**
|
|
290
|
+
* Buffered sink calls per activation
|
|
291
|
+
*/
|
|
292
|
+
sinkCalls = Array();
|
|
293
|
+
/**
|
|
294
|
+
* A nanosecond resolution time function, externally injected. This is used to
|
|
295
|
+
* precisely sort logs entries emitted from the Workflow Context vs those emitted
|
|
296
|
+
* from other sources (e.g. main thread, Core, etc).
|
|
297
|
+
*/
|
|
298
|
+
getTimeOfDay;
|
|
299
|
+
registeredActivityNames;
|
|
300
|
+
versioningBehavior;
|
|
301
|
+
workflowDefinitionOptionsGetter;
|
|
302
|
+
constructor({ info, now, showStackTraceSources, sourceMap, getTimeOfDay, randomnessSeed, registeredActivityNames, }) {
|
|
225
303
|
this.getTimeOfDay = getTimeOfDay;
|
|
226
304
|
this.info = info;
|
|
227
305
|
this.now = now;
|
|
@@ -281,6 +359,7 @@ class Activator {
|
|
|
281
359
|
return {
|
|
282
360
|
commands: this.commands.splice(0),
|
|
283
361
|
usedInternalFlags: [...this.knownFlags],
|
|
362
|
+
versioningBehavior: this.versioningBehavior,
|
|
284
363
|
};
|
|
285
364
|
}
|
|
286
365
|
async startWorkflowNextHandler({ args }) {
|
|
@@ -302,13 +381,17 @@ class Activator {
|
|
|
302
381
|
// Most things related to initialization have already been handled in the constructor
|
|
303
382
|
this.mutateWorkflowInfo((info) => ({
|
|
304
383
|
...info,
|
|
305
|
-
searchAttributes: (0,
|
|
384
|
+
searchAttributes: (0, payload_search_attributes_1.decodeSearchAttributes)(searchAttributes?.indexedFields),
|
|
385
|
+
typedSearchAttributes: (0, payload_search_attributes_1.decodeTypedSearchAttributes)(searchAttributes?.indexedFields),
|
|
306
386
|
memo: (0, common_1.mapFromPayloads)(this.payloadConverter, memo?.fields),
|
|
307
387
|
lastResult: (0, common_1.fromPayloadsAtIndex)(this.payloadConverter, 0, lastCompletionResult?.payloads),
|
|
308
388
|
lastFailure: continuedFailure != null
|
|
309
389
|
? this.failureConverter.failureToError(continuedFailure, this.payloadConverter)
|
|
310
390
|
: undefined,
|
|
311
391
|
}));
|
|
392
|
+
if (this.workflowDefinitionOptionsGetter) {
|
|
393
|
+
this.versioningBehavior = this.workflowDefinitionOptionsGetter().versioningBehavior;
|
|
394
|
+
}
|
|
312
395
|
}
|
|
313
396
|
cancelWorkflow(_activation) {
|
|
314
397
|
this.cancelled = true;
|
|
@@ -393,14 +476,25 @@ class Activator {
|
|
|
393
476
|
reject(this.failureToError(failure));
|
|
394
477
|
}
|
|
395
478
|
}
|
|
479
|
+
resolveNexusOperationStart(_) {
|
|
480
|
+
throw new Error('TODO');
|
|
481
|
+
}
|
|
482
|
+
resolveNexusOperation(_) {
|
|
483
|
+
throw new Error('TODO');
|
|
484
|
+
}
|
|
396
485
|
// Intentionally non-async function so this handler doesn't show up in the stack trace
|
|
397
486
|
queryWorkflowNextHandler({ queryName, args }) {
|
|
398
|
-
|
|
487
|
+
let fn = this.queryHandlers.get(queryName)?.handler;
|
|
488
|
+
if (fn === undefined && this.defaultQueryHandler !== undefined) {
|
|
489
|
+
fn = this.defaultQueryHandler.bind(undefined, queryName);
|
|
490
|
+
}
|
|
491
|
+
// No handler or default registered, fail.
|
|
399
492
|
if (fn === undefined) {
|
|
400
493
|
const knownQueryTypes = [...this.queryHandlers.keys()].join(' ');
|
|
401
494
|
// Fail the query
|
|
402
495
|
return Promise.reject(new ReferenceError(`Workflow did not register a handler for ${queryName}. Registered queries: [${knownQueryTypes}]`));
|
|
403
496
|
}
|
|
497
|
+
// Execute handler.
|
|
404
498
|
try {
|
|
405
499
|
const ret = fn(...args);
|
|
406
500
|
if (ret instanceof Promise) {
|
|
@@ -436,8 +530,17 @@ class Activator {
|
|
|
436
530
|
if (!protocolInstanceId) {
|
|
437
531
|
throw new TypeError('Missing activation update protocolInstanceId');
|
|
438
532
|
}
|
|
439
|
-
const entry = this.updateHandlers.get(name)
|
|
440
|
-
|
|
533
|
+
const entry = this.updateHandlers.get(name) ??
|
|
534
|
+
(this.defaultUpdateHandler
|
|
535
|
+
? {
|
|
536
|
+
handler: this.defaultUpdateHandler.bind(undefined, name),
|
|
537
|
+
validator: undefined,
|
|
538
|
+
// Default to a warning policy.
|
|
539
|
+
unfinishedPolicy: common_1.HandlerUnfinishedPolicy.WARN_AND_ABANDON,
|
|
540
|
+
}
|
|
541
|
+
: null);
|
|
542
|
+
// If we don't have an entry from either source, buffer and return
|
|
543
|
+
if (entry === null) {
|
|
441
544
|
this.bufferedUpdates.push(activation);
|
|
442
545
|
return;
|
|
443
546
|
}
|
|
@@ -498,7 +601,7 @@ class Activator {
|
|
|
498
601
|
this.rejectUpdate(protocolInstanceId, error);
|
|
499
602
|
}
|
|
500
603
|
else {
|
|
501
|
-
|
|
604
|
+
this.handleWorkflowFailure(error);
|
|
502
605
|
}
|
|
503
606
|
})
|
|
504
607
|
.finally(() => this.inProgressUpdates.delete(updateId));
|
|
@@ -518,13 +621,22 @@ class Activator {
|
|
|
518
621
|
dispatchBufferedUpdates() {
|
|
519
622
|
const bufferedUpdates = this.bufferedUpdates;
|
|
520
623
|
while (bufferedUpdates.length) {
|
|
521
|
-
|
|
522
|
-
if (
|
|
523
|
-
|
|
524
|
-
|
|
624
|
+
// We have a default update handler, so all updates are dispatchable.
|
|
625
|
+
if (this.defaultUpdateHandler) {
|
|
626
|
+
const update = bufferedUpdates.shift();
|
|
627
|
+
// Logically, this must be defined as we're in the loop.
|
|
628
|
+
// But Typescript doesn't know that so we use a non-null assertion (!).
|
|
629
|
+
this.doUpdate(update);
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
const foundIndex = bufferedUpdates.findIndex((update) => this.updateHandlers.has(update.name));
|
|
633
|
+
if (foundIndex === -1) {
|
|
634
|
+
// No buffered Updates have a handler yet.
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
const [update] = bufferedUpdates.splice(foundIndex, 1);
|
|
638
|
+
this.doUpdate(update);
|
|
525
639
|
}
|
|
526
|
-
const [update] = bufferedUpdates.splice(foundIndex, 1);
|
|
527
|
-
this.doUpdate(update);
|
|
528
640
|
}
|
|
529
641
|
}
|
|
530
642
|
rejectBufferedUpdates() {
|
|
@@ -609,6 +721,8 @@ class Activator {
|
|
|
609
721
|
}
|
|
610
722
|
}
|
|
611
723
|
warnIfUnfinishedHandlers() {
|
|
724
|
+
if (this.workflowTaskError)
|
|
725
|
+
return;
|
|
612
726
|
const getWarnable = (handlerExecutions) => {
|
|
613
727
|
return Array.from(handlerExecutions).filter((ex) => ex.unfinishedPolicy === common_1.HandlerUnfinishedPolicy.WARN_AND_ABANDON);
|
|
614
728
|
};
|
|
@@ -709,19 +823,14 @@ class Activator {
|
|
|
709
823
|
* Transforms failures into a command to be sent to the server.
|
|
710
824
|
* Used to handle any failure emitted by the Workflow.
|
|
711
825
|
*/
|
|
712
|
-
|
|
826
|
+
handleWorkflowFailure(error) {
|
|
713
827
|
if (this.cancelled && (0, errors_1.isCancellation)(error)) {
|
|
714
828
|
this.pushCommand({ cancelWorkflowExecution: {} }, true);
|
|
715
829
|
}
|
|
716
830
|
else if (error instanceof interfaces_1.ContinueAsNew) {
|
|
717
831
|
this.pushCommand({ continueAsNewWorkflowExecution: error.command }, true);
|
|
718
832
|
}
|
|
719
|
-
else {
|
|
720
|
-
if (!(error instanceof common_1.TemporalFailure)) {
|
|
721
|
-
// This results in an unhandled rejection which will fail the activation
|
|
722
|
-
// preventing it from completing.
|
|
723
|
-
throw error;
|
|
724
|
-
}
|
|
833
|
+
else if (error instanceof common_1.TemporalFailure) {
|
|
725
834
|
// Fail the workflow. We do not want to issue unfinishedHandlers warnings. To achieve that, we
|
|
726
835
|
// mark all handlers as completed now.
|
|
727
836
|
this.inProgressSignals.clear();
|
|
@@ -732,6 +841,27 @@ class Activator {
|
|
|
732
841
|
},
|
|
733
842
|
}, true);
|
|
734
843
|
}
|
|
844
|
+
else {
|
|
845
|
+
this.recordWorkflowTaskError(error);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
recordWorkflowTaskError(error) {
|
|
849
|
+
// Only keep the first error that bubbles up; subsequent errors will be ignored.
|
|
850
|
+
if (this.workflowTaskError === undefined)
|
|
851
|
+
this.workflowTaskError = error;
|
|
852
|
+
// Immediately rethrow the error if we know it is safe to do so (i.e. we are not running async
|
|
853
|
+
// microtasks). Otherwise, the error will be rethrown whenever we get an opportunity to do so,
|
|
854
|
+
// e.g. the next time `tryUnblockConditions()` is called.
|
|
855
|
+
if (this.rethrowSynchronously)
|
|
856
|
+
this.maybeRethrowWorkflowTaskError();
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* If a Workflow Task error was captured, and we are running in synchronous mode,
|
|
860
|
+
* then bubble it up now. This is safe to call even if there is no error to rethrow.
|
|
861
|
+
*/
|
|
862
|
+
maybeRethrowWorkflowTaskError() {
|
|
863
|
+
if (this.workflowTaskError)
|
|
864
|
+
throw this.workflowTaskError;
|
|
735
865
|
}
|
|
736
866
|
completeQuery(queryId, result) {
|
|
737
867
|
this.pushCommand({
|