@temporalio/workflow 1.11.8 → 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 -7
- package/lib/internals.js +323 -201
- 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 -33
- 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/src/metrics.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MetricCounter,
|
|
3
|
+
MetricGauge,
|
|
4
|
+
MetricHistogram,
|
|
5
|
+
MetricMeter,
|
|
6
|
+
MetricMeterWithComposedTags,
|
|
7
|
+
MetricTags,
|
|
8
|
+
NumericMetricValueType,
|
|
9
|
+
} from '@temporalio/common';
|
|
10
|
+
import { composeInterceptors } from '@temporalio/common/lib/interceptors';
|
|
11
|
+
import { proxySinks, Sink, Sinks } from './sinks';
|
|
12
|
+
import { workflowInfo } from './workflow';
|
|
13
|
+
import { assertInWorkflowContext } from './global-attributes';
|
|
14
|
+
|
|
15
|
+
class WorkflowMetricMeterImpl implements MetricMeter {
|
|
16
|
+
constructor() {}
|
|
17
|
+
|
|
18
|
+
createCounter(name: string, unit?: string, description?: string): MetricCounter {
|
|
19
|
+
assertInWorkflowContext("Workflow's `metricMeter` can only be used while in Workflow Context");
|
|
20
|
+
return new WorkflowMetricCounter(name, unit, description);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
createHistogram(
|
|
24
|
+
name: string,
|
|
25
|
+
valueType: NumericMetricValueType = 'int',
|
|
26
|
+
unit?: string,
|
|
27
|
+
description?: string
|
|
28
|
+
): MetricHistogram {
|
|
29
|
+
assertInWorkflowContext("Workflow's `metricMeter` can only be used while in Workflow Context");
|
|
30
|
+
return new WorkflowMetricHistogram(name, valueType, unit, description);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
createGauge(
|
|
34
|
+
name: string,
|
|
35
|
+
valueType: NumericMetricValueType = 'int',
|
|
36
|
+
unit?: string,
|
|
37
|
+
description?: string
|
|
38
|
+
): MetricGauge {
|
|
39
|
+
assertInWorkflowContext("Workflow's `metricMeter` can only be used while in Workflow Context");
|
|
40
|
+
return new WorkflowMetricGauge(name, valueType, unit, description);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
withTags(_tags: MetricTags): MetricMeter {
|
|
44
|
+
assertInWorkflowContext("Workflow's `metricMeter` can only be used while in Workflow Context");
|
|
45
|
+
// Tags composition is handled by a MetricMeterWithComposedTags wrapper over this one
|
|
46
|
+
throw new Error(`withTags is not supported directly on WorkflowMetricMeter`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
class WorkflowMetricCounter implements MetricCounter {
|
|
51
|
+
constructor(
|
|
52
|
+
public readonly name: string,
|
|
53
|
+
public readonly unit: string | undefined,
|
|
54
|
+
public readonly description: string | undefined
|
|
55
|
+
) {}
|
|
56
|
+
|
|
57
|
+
add(value: number, extraTags: MetricTags = {}): void {
|
|
58
|
+
if (value < 0) {
|
|
59
|
+
throw new Error(`MetricCounter value must be non-negative (got ${value})`);
|
|
60
|
+
}
|
|
61
|
+
if (!workflowInfo().unsafe.isReplaying) {
|
|
62
|
+
metricSink.addMetricCounterValue(this.name, this.unit, this.description, value, extraTags);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
withTags(_tags: MetricTags): MetricCounter {
|
|
67
|
+
// Tags composition is handled by a MetricMeterWithComposedTags wrapper over this one
|
|
68
|
+
throw new Error(`withTags is not supported directly on WorkflowMetricCounter`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
class WorkflowMetricHistogram implements MetricHistogram {
|
|
73
|
+
constructor(
|
|
74
|
+
public readonly name: string,
|
|
75
|
+
public readonly valueType: NumericMetricValueType,
|
|
76
|
+
public readonly unit: string | undefined,
|
|
77
|
+
public readonly description: string | undefined
|
|
78
|
+
) {}
|
|
79
|
+
|
|
80
|
+
record(value: number, extraTags: MetricTags = {}): void {
|
|
81
|
+
if (value < 0) {
|
|
82
|
+
throw new Error(`MetricHistogram value must be non-negative (got ${value})`);
|
|
83
|
+
}
|
|
84
|
+
if (!workflowInfo().unsafe.isReplaying) {
|
|
85
|
+
metricSink.recordMetricHistogramValue(this.name, this.valueType, this.unit, this.description, value, extraTags);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
withTags(_tags: MetricTags): MetricHistogram {
|
|
90
|
+
// Tags composition is handled by a MetricMeterWithComposedTags wrapper over this one
|
|
91
|
+
throw new Error(`withTags is not supported directly on WorkflowMetricHistogram`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
class WorkflowMetricGauge implements MetricGauge {
|
|
96
|
+
constructor(
|
|
97
|
+
public readonly name: string,
|
|
98
|
+
public readonly valueType: NumericMetricValueType,
|
|
99
|
+
public readonly unit: string | undefined,
|
|
100
|
+
public readonly description: string | undefined
|
|
101
|
+
) {}
|
|
102
|
+
|
|
103
|
+
set(value: number, tags?: MetricTags): void {
|
|
104
|
+
if (value < 0) {
|
|
105
|
+
throw new Error(`MetricGauge value must be non-negative (got ${value})`);
|
|
106
|
+
}
|
|
107
|
+
if (!workflowInfo().unsafe.isReplaying) {
|
|
108
|
+
metricSink.setMetricGaugeValue(this.name, this.valueType, this.unit, this.description, value, tags ?? {});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
withTags(_tags: MetricTags): MetricGauge {
|
|
113
|
+
// Tags composition is handled by a MetricMeterWithComposedTags wrapper over this one
|
|
114
|
+
throw new Error(`withTags is not supported directly on WorkflowMetricGauge`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
119
|
+
|
|
120
|
+
// Note: given that forwarding metrics outside of the sanbox can be quite chatty and add non
|
|
121
|
+
// negligeable overhead, we eagerly check for `isReplaying` and completely skip doing sink
|
|
122
|
+
// calls if we are replaying.
|
|
123
|
+
const metricSink = proxySinks<MetricSinks>().__temporal_metrics;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Sink interface for forwarding metrics from the Workflow sandbox to the Worker.
|
|
127
|
+
*
|
|
128
|
+
* These sink functions are not intended to be called directly from workflow code; instead,
|
|
129
|
+
* developers should use the `metricMeter` object exposed to workflow code by the SDK, which
|
|
130
|
+
* provides an API that is easier to work with.
|
|
131
|
+
*
|
|
132
|
+
* This sink interface is also not meant to be implemented by user.
|
|
133
|
+
*
|
|
134
|
+
* @hidden
|
|
135
|
+
* @internal Users should not implement this interface, nor use it directly. Use `metricMeter` instead.
|
|
136
|
+
*/
|
|
137
|
+
export interface MetricSinks extends Sinks {
|
|
138
|
+
__temporal_metrics: WorkflowMetricMeter;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @hidden
|
|
143
|
+
* @internal Users should not implement this interface, nor use it directly. Use `metricMeter` instead.
|
|
144
|
+
*/
|
|
145
|
+
export interface WorkflowMetricMeter extends Sink {
|
|
146
|
+
addMetricCounterValue(
|
|
147
|
+
metricName: string,
|
|
148
|
+
unit: string | undefined,
|
|
149
|
+
description: string | undefined,
|
|
150
|
+
value: number,
|
|
151
|
+
attrs: MetricTags
|
|
152
|
+
): void;
|
|
153
|
+
|
|
154
|
+
recordMetricHistogramValue(
|
|
155
|
+
metricName: string,
|
|
156
|
+
valueType: NumericMetricValueType,
|
|
157
|
+
unit: string | undefined,
|
|
158
|
+
description: string | undefined,
|
|
159
|
+
value: number,
|
|
160
|
+
attrs: MetricTags
|
|
161
|
+
): void;
|
|
162
|
+
|
|
163
|
+
setMetricGaugeValue(
|
|
164
|
+
metricName: string,
|
|
165
|
+
valueType: NumericMetricValueType,
|
|
166
|
+
unit: string | undefined,
|
|
167
|
+
description: string | undefined,
|
|
168
|
+
value: number,
|
|
169
|
+
attrs: MetricTags
|
|
170
|
+
): void;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* A MetricMeter that can be used to emit metrics from within a Workflow.
|
|
175
|
+
*
|
|
176
|
+
* @experimental The Metric API is an experimental feature and may be subject to change.
|
|
177
|
+
*/
|
|
178
|
+
export const metricMeter: MetricMeter = MetricMeterWithComposedTags.compose(
|
|
179
|
+
new WorkflowMetricMeterImpl(),
|
|
180
|
+
() => {
|
|
181
|
+
const activator = assertInWorkflowContext('Workflow.metricMeter may only be used from workflow context.');
|
|
182
|
+
const getMetricTags = composeInterceptors(activator.interceptors.outbound, 'getMetricTags', (a) => a);
|
|
183
|
+
|
|
184
|
+
const info = activator.info;
|
|
185
|
+
return getMetricTags({
|
|
186
|
+
// namespace and taskQueue will be added by the Worker
|
|
187
|
+
workflowType: info.workflowType,
|
|
188
|
+
});
|
|
189
|
+
},
|
|
190
|
+
true
|
|
191
|
+
);
|
package/src/worker-interface.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import { IllegalStateError } from '@temporalio/common';
|
|
6
|
+
import { encodeVersioningBehavior, IllegalStateError, WorkflowFunctionWithOptions } from '@temporalio/common';
|
|
7
7
|
import { composeInterceptors } from '@temporalio/common/lib/interceptors';
|
|
8
8
|
import { coresdk } from '@temporalio/proto';
|
|
9
9
|
import { disableStorage } from './cancellation-scope';
|
|
@@ -37,54 +37,68 @@ export function initRuntime(options: WorkflowCreateOptionsInternal): void {
|
|
|
37
37
|
// as well as Date and Math.random.
|
|
38
38
|
setActivatorUntyped(activator);
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
activator.rethrowSynchronously = true;
|
|
41
|
+
try {
|
|
42
|
+
// webpack alias to payloadConverterPath
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
44
|
+
const customPayloadConverter = require('__temporal_custom_payload_converter').payloadConverter;
|
|
45
|
+
// The `payloadConverter` export is validated in the Worker
|
|
46
|
+
if (customPayloadConverter != null) {
|
|
47
|
+
activator.payloadConverter = customPayloadConverter;
|
|
48
|
+
}
|
|
49
|
+
// webpack alias to failureConverterPath
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
51
|
+
const customFailureConverter = require('__temporal_custom_failure_converter').failureConverter;
|
|
52
|
+
// The `failureConverter` export is validated in the Worker
|
|
53
|
+
if (customFailureConverter != null) {
|
|
54
|
+
activator.failureConverter = customFailureConverter;
|
|
55
|
+
}
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
const { importWorkflows, importInterceptors } = global.__TEMPORAL__;
|
|
58
|
+
if (importWorkflows === undefined || importInterceptors === undefined) {
|
|
59
|
+
throw new IllegalStateError('Workflow bundle did not register import hooks');
|
|
60
|
+
}
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
const interceptors = importInterceptors();
|
|
63
|
+
for (const mod of interceptors) {
|
|
64
|
+
const factory: WorkflowInterceptorsFactory = mod.interceptors;
|
|
65
|
+
if (factory !== undefined) {
|
|
66
|
+
if (typeof factory !== 'function') {
|
|
67
|
+
throw new TypeError(
|
|
68
|
+
`Failed to initialize workflows interceptors: expected a function, but got: '${factory}'`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const interceptors = factory();
|
|
72
|
+
activator.interceptors.inbound.push(...(interceptors.inbound ?? []));
|
|
73
|
+
activator.interceptors.outbound.push(...(interceptors.outbound ?? []));
|
|
74
|
+
activator.interceptors.internals.push(...(interceptors.internals ?? []));
|
|
66
75
|
}
|
|
67
|
-
const interceptors = factory();
|
|
68
|
-
activator.interceptors.inbound.push(...(interceptors.inbound ?? []));
|
|
69
|
-
activator.interceptors.outbound.push(...(interceptors.outbound ?? []));
|
|
70
|
-
activator.interceptors.internals.push(...(interceptors.internals ?? []));
|
|
71
76
|
}
|
|
72
|
-
}
|
|
73
77
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
const mod = importWorkflows();
|
|
79
|
+
const workflowFn = mod[activator.info.workflowType];
|
|
80
|
+
const defaultWorkflowFn = mod['default'];
|
|
81
|
+
|
|
82
|
+
if (typeof workflowFn === 'function') {
|
|
83
|
+
activator.workflow = workflowFn;
|
|
84
|
+
} else if (typeof defaultWorkflowFn === 'function') {
|
|
85
|
+
activator.workflow = defaultWorkflowFn;
|
|
86
|
+
} else {
|
|
87
|
+
const details =
|
|
88
|
+
workflowFn === undefined
|
|
89
|
+
? 'no such function is exported by the workflow bundle'
|
|
90
|
+
: `expected a function, but got: '${typeof workflowFn}'`;
|
|
91
|
+
throw new TypeError(`Failed to initialize workflow of type '${activator.info.workflowType}': ${details}`);
|
|
92
|
+
}
|
|
93
|
+
if (isWorkflowFunctionWithOptions(activator.workflow)) {
|
|
94
|
+
if (typeof activator.workflow.workflowDefinitionOptions === 'object') {
|
|
95
|
+
activator.versioningBehavior = activator.workflow.workflowDefinitionOptions.versioningBehavior;
|
|
96
|
+
} else {
|
|
97
|
+
activator.workflowDefinitionOptionsGetter = activator.workflow.workflowDefinitionOptions;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} finally {
|
|
101
|
+
activator.rethrowSynchronously = false;
|
|
88
102
|
}
|
|
89
103
|
}
|
|
90
104
|
|
|
@@ -111,53 +125,70 @@ function fixPrototypes<X>(obj: X): X {
|
|
|
111
125
|
* Initialize the workflow. Or to be exact, _complete_ initialization, as most part has been done in constructor).
|
|
112
126
|
*/
|
|
113
127
|
export function initialize(initializeWorkflowJob: coresdk.workflow_activation.IInitializeWorkflow): void {
|
|
114
|
-
getActivator()
|
|
128
|
+
const activator = getActivator();
|
|
129
|
+
activator.rethrowSynchronously = true;
|
|
130
|
+
try {
|
|
131
|
+
activator.initializeWorkflow(initializeWorkflowJob);
|
|
132
|
+
} finally {
|
|
133
|
+
activator.rethrowSynchronously = false;
|
|
134
|
+
}
|
|
115
135
|
}
|
|
116
136
|
|
|
117
137
|
/**
|
|
118
|
-
* Run a chunk of activation jobs
|
|
138
|
+
* Run a chunk of activation jobs.
|
|
139
|
+
*
|
|
140
|
+
* Notice that this function is not async and runs _inside_ the VM context. Therefore, no microtask
|
|
141
|
+
* will get executed _while_ this function is active; they will however get executed _after_ this
|
|
142
|
+
* function returns (i.e. all outstanding microtasks in the VM will get executed before execution
|
|
143
|
+
* resumes out of the VM, in `vm-shared.ts:activate()`).
|
|
119
144
|
*/
|
|
120
145
|
export function activate(activation: coresdk.workflow_activation.IWorkflowActivation, batchIndex = 0): void {
|
|
121
146
|
const activator = getActivator();
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
147
|
+
activator.rethrowSynchronously = true;
|
|
148
|
+
try {
|
|
149
|
+
const intercept = composeInterceptors(activator.interceptors.internals, 'activate', ({ activation }) => {
|
|
150
|
+
// Cast from the interface to the class which has the `variant` attribute.
|
|
151
|
+
// This is safe because we know that activation is a proto class.
|
|
152
|
+
const jobs = activation.jobs as coresdk.workflow_activation.WorkflowActivationJob[];
|
|
126
153
|
|
|
127
|
-
|
|
128
|
-
|
|
154
|
+
// Initialization will have been handled already, but we might still need to start the workflow function
|
|
155
|
+
const startWorkflowJob = jobs[0].variant === 'initializeWorkflow' ? jobs.shift()?.initializeWorkflow : undefined;
|
|
129
156
|
|
|
130
|
-
|
|
131
|
-
|
|
157
|
+
for (const job of jobs) {
|
|
158
|
+
if (job.variant === undefined) throw new TypeError('Expected job.variant to be defined');
|
|
132
159
|
|
|
133
|
-
|
|
134
|
-
|
|
160
|
+
const variant = job[job.variant];
|
|
161
|
+
if (!variant) throw new TypeError(`Expected job.${job.variant} to be set`);
|
|
135
162
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (job.variant !== 'queryWorkflow') tryUnblockConditions();
|
|
139
|
-
}
|
|
163
|
+
activator[job.variant](variant as any /* TS can't infer this type */);
|
|
140
164
|
|
|
141
|
-
|
|
142
|
-
const safeJobTypes: coresdk.workflow_activation.WorkflowActivationJob['variant'][] = [
|
|
143
|
-
'initializeWorkflow',
|
|
144
|
-
'signalWorkflow',
|
|
145
|
-
'doUpdate',
|
|
146
|
-
'cancelWorkflow',
|
|
147
|
-
'updateRandomSeed',
|
|
148
|
-
];
|
|
149
|
-
if (jobs.some((job) => !safeJobTypes.includes(job.variant))) {
|
|
150
|
-
throw new TypeError(
|
|
151
|
-
'Received both initializeWorkflow and non-signal/non-update jobs in the same activation: ' +
|
|
152
|
-
JSON.stringify(jobs.map((job) => job.variant))
|
|
153
|
-
);
|
|
165
|
+
if (job.variant !== 'queryWorkflow') tryUnblockConditions();
|
|
154
166
|
}
|
|
155
167
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
168
|
+
if (startWorkflowJob) {
|
|
169
|
+
const safeJobTypes: coresdk.workflow_activation.WorkflowActivationJob['variant'][] = [
|
|
170
|
+
'initializeWorkflow',
|
|
171
|
+
'signalWorkflow',
|
|
172
|
+
'doUpdate',
|
|
173
|
+
'cancelWorkflow',
|
|
174
|
+
'updateRandomSeed',
|
|
175
|
+
];
|
|
176
|
+
if (jobs.some((job) => !safeJobTypes.includes(job.variant))) {
|
|
177
|
+
throw new TypeError(
|
|
178
|
+
'Received both initializeWorkflow and non-signal/non-update jobs in the same activation: ' +
|
|
179
|
+
JSON.stringify(jobs.map((job) => job.variant))
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
activator.startWorkflow(startWorkflowJob);
|
|
184
|
+
|
|
185
|
+
tryUnblockConditions();
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
intercept({ activation, batchIndex });
|
|
189
|
+
} finally {
|
|
190
|
+
activator.rethrowSynchronously = false;
|
|
191
|
+
}
|
|
161
192
|
}
|
|
162
193
|
|
|
163
194
|
/**
|
|
@@ -168,18 +199,26 @@ export function activate(activation: coresdk.workflow_activation.IWorkflowActiva
|
|
|
168
199
|
*/
|
|
169
200
|
export function concludeActivation(): coresdk.workflow_completion.IWorkflowActivationCompletion {
|
|
170
201
|
const activator = getActivator();
|
|
171
|
-
activator.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
202
|
+
activator.rethrowSynchronously = true;
|
|
203
|
+
try {
|
|
204
|
+
activator.rejectBufferedUpdates();
|
|
205
|
+
const intercept = composeInterceptors(activator.interceptors.internals, 'concludeActivation', (input) => input);
|
|
206
|
+
const activationCompletion = activator.concludeActivation();
|
|
207
|
+
const { commands } = intercept({ commands: activationCompletion.commands });
|
|
208
|
+
if (activator.completed) {
|
|
209
|
+
activator.warnIfUnfinishedHandlers();
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
runId: activator.info.runId,
|
|
213
|
+
successful: {
|
|
214
|
+
...activationCompletion,
|
|
215
|
+
commands,
|
|
216
|
+
versioningBehavior: encodeVersioningBehavior(activationCompletion.versioningBehavior),
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
} finally {
|
|
220
|
+
activator.rethrowSynchronously = false;
|
|
177
221
|
}
|
|
178
|
-
|
|
179
|
-
return {
|
|
180
|
-
runId: activator.info.runId,
|
|
181
|
-
successful: { ...activationCompletion, commands },
|
|
182
|
-
};
|
|
183
222
|
}
|
|
184
223
|
|
|
185
224
|
/**
|
|
@@ -188,28 +227,46 @@ export function concludeActivation(): coresdk.workflow_completion.IWorkflowActiv
|
|
|
188
227
|
* @returns number of unblocked conditions.
|
|
189
228
|
*/
|
|
190
229
|
export function tryUnblockConditions(): number {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
230
|
+
const activator = getActivator();
|
|
231
|
+
activator.rethrowSynchronously = true;
|
|
232
|
+
try {
|
|
233
|
+
let numUnblocked = 0;
|
|
234
|
+
for (;;) {
|
|
235
|
+
activator.maybeRethrowWorkflowTaskError();
|
|
236
|
+
const prevUnblocked = numUnblocked;
|
|
237
|
+
for (const [seq, cond] of activator.blockedConditions.entries()) {
|
|
238
|
+
if (cond.fn()) {
|
|
239
|
+
cond.resolve();
|
|
240
|
+
numUnblocked++;
|
|
241
|
+
// It is safe to delete elements during map iteration
|
|
242
|
+
activator.blockedConditions.delete(seq);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (prevUnblocked === numUnblocked) {
|
|
246
|
+
break;
|
|
200
247
|
}
|
|
201
248
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
249
|
+
return numUnblocked;
|
|
250
|
+
} finally {
|
|
251
|
+
activator.rethrowSynchronously = false;
|
|
205
252
|
}
|
|
206
|
-
return numUnblocked;
|
|
207
253
|
}
|
|
208
254
|
|
|
209
255
|
export function dispose(): void {
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
256
|
+
const activator = getActivator();
|
|
257
|
+
activator.rethrowSynchronously = true;
|
|
258
|
+
try {
|
|
259
|
+
const dispose = composeInterceptors(activator.interceptors.internals, 'dispose', async () => {
|
|
260
|
+
disableStorage();
|
|
261
|
+
disableUpdateStorage();
|
|
262
|
+
});
|
|
263
|
+
dispose({});
|
|
264
|
+
} finally {
|
|
265
|
+
activator.rethrowSynchronously = false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function isWorkflowFunctionWithOptions(obj: any): obj is WorkflowFunctionWithOptions<any[], any> {
|
|
270
|
+
if (obj == null) return false;
|
|
271
|
+
return Object.hasOwn(obj, 'workflowDefinitionOptions');
|
|
215
272
|
}
|