@fsai-flow/core 0.0.4 → 0.1.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/dist/index.d.ts +17 -0
- package/dist/index.js +61 -0
- package/dist/{src/lib → lib}/ActiveWebhooks.d.ts +1 -1
- package/dist/lib/ActiveWebhooks.js +177 -0
- package/dist/{src/lib → lib}/ActiveWorkflows.d.ts +3 -3
- package/dist/lib/ActiveWorkflows.js +465 -0
- package/dist/{src/lib → lib}/BinaryDataManager/FileSystem.d.ts +1 -1
- package/dist/lib/BinaryDataManager/FileSystem.js +180 -0
- package/dist/{src/lib → lib}/BinaryDataManager/index.d.ts +2 -2
- package/dist/lib/BinaryDataManager/index.js +129 -0
- package/dist/{src/lib → lib}/ChangeCase.js +11 -11
- package/dist/lib/Constants.js +18 -0
- package/dist/{src/lib → lib}/Credentials.d.ts +1 -1
- package/dist/{src/lib → lib}/Credentials.js +7 -8
- package/dist/{src/lib → lib}/FileSystem.d.ts +1 -1
- package/dist/lib/FileSystem.js +180 -0
- package/dist/{src/lib → lib}/InputConnectionDataLegacy.d.ts +1 -1
- package/dist/lib/InputConnectionDataLegacy.js +72 -0
- package/dist/{src/lib → lib}/Interfaces.d.ts +47 -48
- package/dist/{src/lib → lib}/Interfaces.js +0 -1
- package/dist/{src/lib → lib}/LoadNodeParameterOptions.d.ts +1 -1
- package/dist/lib/LoadNodeParameterOptions.js +152 -0
- package/dist/{src/lib → lib}/NodeExecuteFunctions.d.ts +9 -10
- package/dist/lib/NodeExecuteFunctions.js +2467 -0
- package/dist/{src/lib → lib}/NodesLoader/constants.d.ts +1 -1
- package/dist/lib/NodesLoader/constants.js +105 -0
- package/dist/{src/lib → lib}/NodesLoader/custom-directory-loader.d.ts +1 -1
- package/dist/lib/NodesLoader/custom-directory-loader.js +35 -0
- package/dist/{src/lib → lib}/NodesLoader/directory-loader.d.ts +1 -1
- package/dist/{src/lib → lib}/NodesLoader/directory-loader.js +80 -38
- package/dist/lib/NodesLoader/index.d.ts +5 -0
- package/dist/{src/lib → lib}/NodesLoader/index.js +5 -6
- package/dist/{src/lib → lib}/NodesLoader/lazy-package-directory-loader.d.ts +1 -1
- package/dist/lib/NodesLoader/lazy-package-directory-loader.js +44 -0
- package/dist/{src/lib → lib}/NodesLoader/load-class-in-isolation.js +6 -11
- package/dist/{src/lib → lib}/NodesLoader/package-directory-loader.d.ts +2 -2
- package/dist/{src/lib → lib}/NodesLoader/package-directory-loader.js +28 -36
- package/dist/{src/lib → lib}/NodesLoader/types.js +0 -1
- package/dist/{src/lib → lib}/RedisLeaderElectionManager.d.ts +1 -1
- package/dist/lib/RedisLeaderElectionManager.js +279 -0
- package/dist/lib/RequestTypes.d.ts +58 -0
- package/dist/lib/RequestTypes.js +8 -0
- package/dist/{src/lib → lib}/UserSettings.d.ts +1 -1
- package/dist/lib/UserSettings.js +269 -0
- package/dist/{src/lib → lib}/WorkflowExecute.d.ts +4 -4
- package/dist/{src/lib → lib}/WorkflowExecute.js +230 -178
- package/dist/{src/lib → lib}/index.d.ts +2 -2
- package/dist/lib/index.js +129 -0
- package/dist/{src/utils → utils}/crypto.js +2 -3
- package/package.json +59 -52
- package/dist/README.md +0 -31
- package/dist/package.json +0 -54
- package/dist/src/index.d.ts +0 -16
- package/dist/src/index.js +0 -30
- package/dist/src/index.js.map +0 -1
- package/dist/src/lib/ActiveWebhooks.js +0 -184
- package/dist/src/lib/ActiveWebhooks.js.map +0 -1
- package/dist/src/lib/ActiveWorkflows.js +0 -456
- package/dist/src/lib/ActiveWorkflows.js.map +0 -1
- package/dist/src/lib/BinaryDataManager/FileSystem.js +0 -179
- package/dist/src/lib/BinaryDataManager/FileSystem.js.map +0 -1
- package/dist/src/lib/BinaryDataManager/index.js +0 -146
- package/dist/src/lib/BinaryDataManager/index.js.map +0 -1
- package/dist/src/lib/ChangeCase.js.map +0 -1
- package/dist/src/lib/Constants.js +0 -19
- package/dist/src/lib/Constants.js.map +0 -1
- package/dist/src/lib/Credentials.js.map +0 -1
- package/dist/src/lib/FileSystem.js +0 -179
- package/dist/src/lib/FileSystem.js.map +0 -1
- package/dist/src/lib/InputConnectionDataLegacy.js +0 -79
- package/dist/src/lib/InputConnectionDataLegacy.js.map +0 -1
- package/dist/src/lib/Interfaces.js.map +0 -1
- package/dist/src/lib/LoadNodeParameterOptions.js +0 -150
- package/dist/src/lib/LoadNodeParameterOptions.js.map +0 -1
- package/dist/src/lib/NodeExecuteFunctions.js +0 -2479
- package/dist/src/lib/NodeExecuteFunctions.js.map +0 -1
- package/dist/src/lib/NodesLoader/constants.js +0 -106
- package/dist/src/lib/NodesLoader/constants.js.map +0 -1
- package/dist/src/lib/NodesLoader/custom-directory-loader.js +0 -36
- package/dist/src/lib/NodesLoader/custom-directory-loader.js.map +0 -1
- package/dist/src/lib/NodesLoader/directory-loader.js.map +0 -1
- package/dist/src/lib/NodesLoader/index.d.ts +0 -5
- package/dist/src/lib/NodesLoader/index.js.map +0 -1
- package/dist/src/lib/NodesLoader/lazy-package-directory-loader.js +0 -52
- package/dist/src/lib/NodesLoader/lazy-package-directory-loader.js.map +0 -1
- package/dist/src/lib/NodesLoader/load-class-in-isolation.js.map +0 -1
- package/dist/src/lib/NodesLoader/package-directory-loader.js.map +0 -1
- package/dist/src/lib/NodesLoader/types.js.map +0 -1
- package/dist/src/lib/RedisLeaderElectionManager.js +0 -294
- package/dist/src/lib/RedisLeaderElectionManager.js.map +0 -1
- package/dist/src/lib/UserSettings.js +0 -261
- package/dist/src/lib/UserSettings.js.map +0 -1
- package/dist/src/lib/WorkflowExecute.js.map +0 -1
- package/dist/src/lib/index.js +0 -146
- package/dist/src/lib/index.js.map +0 -1
- package/dist/src/utils/crypto.js.map +0 -1
- package/eslint.config.js +0 -19
- package/jest.config.ts +0 -10
- package/project.json +0 -19
- package/src/index.ts +0 -28
- package/src/lib/ActiveWebhooks.ts +0 -245
- package/src/lib/ActiveWorkflows.ts +0 -575
- package/src/lib/BinaryDataManager/FileSystem.ts +0 -214
- package/src/lib/BinaryDataManager/index.ts +0 -187
- package/src/lib/ChangeCase.ts +0 -45
- package/src/lib/Constants.ts +0 -16
- package/src/lib/Credentials.ts +0 -108
- package/src/lib/FileSystem.ts +0 -214
- package/src/lib/InputConnectionDataLegacy.ts +0 -123
- package/src/lib/Interfaces.ts +0 -338
- package/src/lib/LoadNodeParameterOptions.ts +0 -235
- package/src/lib/NodeExecuteFunctions.ts +0 -3700
- package/src/lib/NodesLoader/constants.ts +0 -112
- package/src/lib/NodesLoader/custom-directory-loader.ts +0 -31
- package/src/lib/NodesLoader/directory-loader.ts +0 -458
- package/src/lib/NodesLoader/index.ts +0 -5
- package/src/lib/NodesLoader/lazy-package-directory-loader.ts +0 -55
- package/src/lib/NodesLoader/load-class-in-isolation.ts +0 -19
- package/src/lib/NodesLoader/package-directory-loader.ts +0 -107
- package/src/lib/NodesLoader/types.ts +0 -14
- package/src/lib/RedisLeaderElectionManager.ts +0 -334
- package/src/lib/UserSettings.ts +0 -292
- package/src/lib/WorkflowExecute.ts +0 -1128
- package/src/lib/index.ts +0 -187
- package/src/utils/crypto.ts +0 -5
- package/tests/Credentials.test.ts +0 -88
- package/tests/Helpers.ts +0 -808
- package/tests/WorkflowExecute.test.ts +0 -1242
- package/tsconfig.json +0 -41
- package/tsconfig.lib.json +0 -10
- package/tsconfig.spec.json +0 -14
- /package/dist/{src/lib → lib}/ChangeCase.d.ts +0 -0
- /package/dist/{src/lib → lib}/Constants.d.ts +0 -0
- /package/dist/{src/lib → lib}/NodesLoader/load-class-in-isolation.d.ts +0 -0
- /package/dist/{src/lib → lib}/NodesLoader/types.d.ts +0 -0
- /package/dist/{src/utils → utils}/crypto.d.ts +0 -0
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.WorkflowExecute = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const PCancelable = require("p-cancelable");
|
|
6
7
|
const workflow_1 = require("@fsai-flow/workflow");
|
|
7
8
|
const lodash_1 = require("lodash");
|
|
9
|
+
const p_cancelable_1 = __importDefault(require("p-cancelable"));
|
|
8
10
|
const __1 = require("..");
|
|
11
|
+
/**
|
|
12
|
+
* Guards against prototype-polluting property keys.
|
|
13
|
+
* Throws if the key would modify Object.prototype when used in a bracket assignment.
|
|
14
|
+
*/
|
|
15
|
+
function assertSafeKey(key) {
|
|
16
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") {
|
|
17
|
+
throw new workflow_1.WorkflowOperationError(`Refusing to use unsafe property key "${key}"`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
9
20
|
class WorkflowExecute {
|
|
10
21
|
constructor(additionalData, mode, runExecutionData) {
|
|
11
22
|
this.additionalData = additionalData;
|
|
@@ -13,12 +24,12 @@ class WorkflowExecute {
|
|
|
13
24
|
this.runExecutionData = runExecutionData || {
|
|
14
25
|
startData: {},
|
|
15
26
|
resultData: {
|
|
16
|
-
runData:
|
|
27
|
+
runData: Object.create(null),
|
|
17
28
|
},
|
|
18
29
|
executionData: {
|
|
19
30
|
contextData: {},
|
|
20
31
|
nodeExecutionStack: [],
|
|
21
|
-
waitingExecution:
|
|
32
|
+
waitingExecution: Object.create(null),
|
|
22
33
|
},
|
|
23
34
|
};
|
|
24
35
|
}
|
|
@@ -37,20 +48,20 @@ class WorkflowExecute {
|
|
|
37
48
|
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
38
49
|
run(workflow, startNode, destinationNode) {
|
|
39
50
|
// Get the nodes to start workflow execution from
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
throw new Error(
|
|
51
|
+
const resolvedStartNode = startNode || workflow.getStartNode(destinationNode);
|
|
52
|
+
if (resolvedStartNode === undefined) {
|
|
53
|
+
throw new Error("No node to start the workflow from could be found!");
|
|
43
54
|
}
|
|
44
55
|
// If a destination node is given we only run the direct parent nodes and no others
|
|
45
56
|
let runNodeFilter;
|
|
46
57
|
if (destinationNode) {
|
|
47
58
|
runNodeFilter = workflow.getParentNodes(destinationNode);
|
|
48
|
-
runNodeFilter
|
|
59
|
+
runNodeFilter?.push(destinationNode);
|
|
49
60
|
}
|
|
50
61
|
// Initialize the data of the start nodes
|
|
51
62
|
const nodeExecutionStack = [
|
|
52
63
|
{
|
|
53
|
-
node:
|
|
64
|
+
node: resolvedStartNode,
|
|
54
65
|
data: {
|
|
55
66
|
main: [
|
|
56
67
|
[
|
|
@@ -68,12 +79,12 @@ class WorkflowExecute {
|
|
|
68
79
|
runNodeFilter,
|
|
69
80
|
},
|
|
70
81
|
resultData: {
|
|
71
|
-
runData:
|
|
82
|
+
runData: Object.create(null),
|
|
72
83
|
},
|
|
73
84
|
executionData: {
|
|
74
85
|
contextData: {},
|
|
75
86
|
nodeExecutionStack,
|
|
76
|
-
waitingExecution:
|
|
87
|
+
waitingExecution: Object.create(null),
|
|
77
88
|
},
|
|
78
89
|
};
|
|
79
90
|
return this.processRunExecutionData(workflow);
|
|
@@ -99,9 +110,10 @@ class WorkflowExecute {
|
|
|
99
110
|
// Initialize the nodeExecutionStack and waitingExecution with
|
|
100
111
|
// the data from runData
|
|
101
112
|
const nodeExecutionStack = [];
|
|
102
|
-
const waitingExecution =
|
|
113
|
+
const waitingExecution = Object.create(null);
|
|
103
114
|
for (const startNode of startNodes) {
|
|
104
|
-
incomingNodeConnections =
|
|
115
|
+
incomingNodeConnections =
|
|
116
|
+
workflow.connectionsByDestinationNode[startNode];
|
|
105
117
|
const incomingData = [];
|
|
106
118
|
if (incomingNodeConnections === undefined) {
|
|
107
119
|
// If it has no incoming data add the default empty data
|
|
@@ -113,7 +125,7 @@ class WorkflowExecute {
|
|
|
113
125
|
}
|
|
114
126
|
else {
|
|
115
127
|
// Get the data of the incoming connections
|
|
116
|
-
for (const connections of incomingNodeConnections[
|
|
128
|
+
for (const connections of incomingNodeConnections["main"]) {
|
|
117
129
|
for (let inputIndex = 0; inputIndex < connections.length; inputIndex++) {
|
|
118
130
|
connection = connections[inputIndex];
|
|
119
131
|
incomingData.push(
|
|
@@ -131,18 +143,22 @@ class WorkflowExecute {
|
|
|
131
143
|
nodeExecutionStack.push(executeData);
|
|
132
144
|
// Check if the destinationNode has to be added as waiting
|
|
133
145
|
// because some input data is already fully available
|
|
134
|
-
incomingNodeConnections =
|
|
146
|
+
incomingNodeConnections =
|
|
147
|
+
workflow.connectionsByDestinationNode[destinationNode];
|
|
135
148
|
if (incomingNodeConnections !== undefined) {
|
|
136
|
-
for (const connections of incomingNodeConnections[
|
|
149
|
+
for (const connections of incomingNodeConnections["main"]) {
|
|
137
150
|
for (let inputIndex = 0; inputIndex < connections.length; inputIndex++) {
|
|
138
151
|
connection = connections[inputIndex];
|
|
152
|
+
assertSafeKey(destinationNode);
|
|
153
|
+
assertSafeKey(connection.type);
|
|
139
154
|
if (waitingExecution[destinationNode] === undefined) {
|
|
140
|
-
waitingExecution[destinationNode] =
|
|
155
|
+
waitingExecution[destinationNode] = Object.create(null);
|
|
141
156
|
}
|
|
142
157
|
if (waitingExecution[destinationNode][runIndex] === undefined) {
|
|
143
|
-
waitingExecution[destinationNode][runIndex] =
|
|
158
|
+
waitingExecution[destinationNode][runIndex] = Object.create(null);
|
|
144
159
|
}
|
|
145
|
-
if (waitingExecution[destinationNode][runIndex][connection.type] ===
|
|
160
|
+
if (waitingExecution[destinationNode][runIndex][connection.type] ===
|
|
161
|
+
undefined) {
|
|
146
162
|
waitingExecution[destinationNode][runIndex][connection.type] = [];
|
|
147
163
|
}
|
|
148
164
|
if (runData[connection.node] !== undefined) {
|
|
@@ -158,10 +174,8 @@ class WorkflowExecute {
|
|
|
158
174
|
}
|
|
159
175
|
}
|
|
160
176
|
// Only run the parent nodes and no others
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
runNodeFilter = workflow.getParentNodes(destinationNode);
|
|
164
|
-
runNodeFilter.push(destinationNode);
|
|
177
|
+
const runNodeFilter = workflow.getParentNodes(destinationNode);
|
|
178
|
+
runNodeFilter?.push(destinationNode);
|
|
165
179
|
this.runExecutionData = {
|
|
166
180
|
startData: {
|
|
167
181
|
destinationNode,
|
|
@@ -182,20 +196,16 @@ class WorkflowExecute {
|
|
|
182
196
|
* Executes the hook with the given name
|
|
183
197
|
*
|
|
184
198
|
* @param {string} hookName
|
|
185
|
-
* @param {
|
|
199
|
+
* @param {unknown[]} parameters
|
|
186
200
|
* @returns {Promise<IRun>}
|
|
187
201
|
* @memberof WorkflowExecute
|
|
188
202
|
*/
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
// eslint-disable-next-line consistent-return
|
|
197
|
-
return this.additionalData.hooks.executeHookFunctions(hookName, parameters);
|
|
198
|
-
});
|
|
203
|
+
async executeHook(hookName, parameters) {
|
|
204
|
+
if (this.additionalData.hooks === undefined) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
// eslint-disable-next-line consistent-return
|
|
208
|
+
return this.additionalData.hooks.executeHookFunctions(hookName, parameters);
|
|
199
209
|
}
|
|
200
210
|
/**
|
|
201
211
|
* Checks the incoming connection does not receive any data
|
|
@@ -204,7 +214,8 @@ class WorkflowExecute {
|
|
|
204
214
|
// for (const inputConnection of workflow.connectionsByDestinationNode[nodeToAdd].main[0]) {
|
|
205
215
|
for (const inputConnection of inputConnections) {
|
|
206
216
|
const nodeIncomingData = (0, lodash_1.get)(runData, `[${inputConnection.node}][${runIndex}].data.main[${inputConnection.index}]`);
|
|
207
|
-
if (nodeIncomingData !== undefined &&
|
|
217
|
+
if (nodeIncomingData !== undefined &&
|
|
218
|
+
nodeIncomingData.length !== 0) {
|
|
208
219
|
return false;
|
|
209
220
|
}
|
|
210
221
|
}
|
|
@@ -214,40 +225,43 @@ class WorkflowExecute {
|
|
|
214
225
|
let stillDataMissing = false;
|
|
215
226
|
// Check if node has multiple inputs as then we have to wait for all input data
|
|
216
227
|
// to be present before we can add it to the node-execution-stack
|
|
217
|
-
if (workflow.connectionsByDestinationNode[connectionData.node][
|
|
228
|
+
if (workflow.connectionsByDestinationNode[connectionData.node]["main"]
|
|
229
|
+
.length > 1) {
|
|
218
230
|
// Node has multiple inputs
|
|
219
231
|
let nodeWasWaiting = true;
|
|
220
232
|
// Check if there is already data for the node
|
|
233
|
+
assertSafeKey(connectionData.node);
|
|
221
234
|
if (this.runExecutionData.executionData.waitingExecution[connectionData.node] === undefined) {
|
|
222
235
|
// Node does not have data yet so create a new empty one
|
|
223
|
-
this.runExecutionData.executionData.waitingExecution[connectionData.node] =
|
|
236
|
+
this.runExecutionData.executionData.waitingExecution[connectionData.node] = Object.create(null);
|
|
224
237
|
nodeWasWaiting = false;
|
|
225
238
|
}
|
|
226
|
-
if (this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex] ===
|
|
227
|
-
undefined) {
|
|
239
|
+
if (this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex] === undefined) {
|
|
228
240
|
// Node does not have data for runIndex yet so create also empty one and init it
|
|
229
241
|
this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex] = {
|
|
230
242
|
main: [],
|
|
231
243
|
};
|
|
232
|
-
for (let i = 0; i <
|
|
233
|
-
|
|
244
|
+
for (let i = 0; i <
|
|
245
|
+
workflow.connectionsByDestinationNode[connectionData.node]["main"]
|
|
246
|
+
.length; i++) {
|
|
247
|
+
this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex]["main"].push(null);
|
|
234
248
|
}
|
|
235
249
|
}
|
|
236
250
|
// Add the new data
|
|
237
251
|
if (nodeSuccessData === null) {
|
|
238
|
-
this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex][
|
|
252
|
+
this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex]["main"][connectionData.index] = null;
|
|
239
253
|
}
|
|
240
254
|
else {
|
|
241
|
-
this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex][
|
|
255
|
+
this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex]["main"][connectionData.index] =
|
|
256
|
+
nodeSuccessData[outputIndex];
|
|
242
257
|
}
|
|
243
258
|
// Check if all data exists now
|
|
244
259
|
let thisExecutionData;
|
|
245
260
|
let allDataFound = true;
|
|
246
261
|
for (let i = 0; i <
|
|
247
|
-
this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex][
|
|
248
|
-
.length; i++) {
|
|
262
|
+
this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex]["main"].length; i++) {
|
|
249
263
|
thisExecutionData =
|
|
250
|
-
this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex][
|
|
264
|
+
this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex]["main"][i];
|
|
251
265
|
if (thisExecutionData === null) {
|
|
252
266
|
allDataFound = false;
|
|
253
267
|
break;
|
|
@@ -262,8 +276,7 @@ class WorkflowExecute {
|
|
|
262
276
|
});
|
|
263
277
|
// Remove the data from waiting
|
|
264
278
|
delete this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex];
|
|
265
|
-
if (Object.keys(this.runExecutionData.executionData.waitingExecution[connectionData.node])
|
|
266
|
-
.length === 0) {
|
|
279
|
+
if (Object.keys(this.runExecutionData.executionData.waitingExecution[connectionData.node]).length === 0) {
|
|
267
280
|
// No more data left for the node so also delete that one
|
|
268
281
|
delete this.runExecutionData.executionData.waitingExecution[connectionData.node];
|
|
269
282
|
}
|
|
@@ -274,13 +287,11 @@ class WorkflowExecute {
|
|
|
274
287
|
// Get a list of all the output nodes that we can check for siblings easier
|
|
275
288
|
const checkOutputNodes = [];
|
|
276
289
|
// eslint-disable-next-line @typescript-eslint/no-for-in-array
|
|
277
|
-
for (const outputIndexParent in workflow.connectionsBySourceNode[parentNodeName][
|
|
278
|
-
if (
|
|
279
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
280
|
-
!workflow.connectionsBySourceNode[parentNodeName]['main'].hasOwnProperty(outputIndexParent)) {
|
|
290
|
+
for (const outputIndexParent in workflow.connectionsBySourceNode[parentNodeName]["main"]) {
|
|
291
|
+
if (!Object.hasOwn(workflow.connectionsBySourceNode[parentNodeName]["main"], outputIndexParent)) {
|
|
281
292
|
continue;
|
|
282
293
|
}
|
|
283
|
-
for (const connectionDataCheck of workflow.connectionsBySourceNode[parentNodeName][
|
|
294
|
+
for (const connectionDataCheck of workflow.connectionsBySourceNode[parentNodeName]["main"][outputIndexParent]) {
|
|
284
295
|
checkOutputNodes.push(connectionDataCheck.node);
|
|
285
296
|
}
|
|
286
297
|
}
|
|
@@ -288,8 +299,10 @@ class WorkflowExecute {
|
|
|
288
299
|
// checked. So we have to go through all the inputs and check if they
|
|
289
300
|
// are already on the list to be processed.
|
|
290
301
|
// If that is not the case add it.
|
|
291
|
-
for (let inputIndex = 0; inputIndex <
|
|
292
|
-
|
|
302
|
+
for (let inputIndex = 0; inputIndex <
|
|
303
|
+
workflow.connectionsByDestinationNode[connectionData.node]["main"]
|
|
304
|
+
.length; inputIndex++) {
|
|
305
|
+
for (const inputData of workflow.connectionsByDestinationNode[connectionData.node]["main"][inputIndex]) {
|
|
293
306
|
if (inputData.node === parentNodeName) {
|
|
294
307
|
// Is the node we come from so its data will be available for sure
|
|
295
308
|
continue;
|
|
@@ -297,12 +310,13 @@ class WorkflowExecute {
|
|
|
297
310
|
const executionStackNodes = this.runExecutionData.executionData.nodeExecutionStack.map((stackData) => stackData.node.name);
|
|
298
311
|
// Check if that node is also an output connection of the
|
|
299
312
|
// previously processed one
|
|
300
|
-
if (inputData.node !== parentNodeName &&
|
|
313
|
+
if (inputData.node !== parentNodeName &&
|
|
314
|
+
checkOutputNodes.includes(inputData.node)) {
|
|
301
315
|
// So the parent node will be added anyway which
|
|
302
316
|
// will then process this node next. So nothing to do
|
|
303
317
|
// unless the incoming data of the node is empty
|
|
304
318
|
// because then it would not be executed
|
|
305
|
-
if (!this.incomingConnectionIsEmpty(this.runExecutionData.resultData.runData, workflow.connectionsByDestinationNode[inputData.node][
|
|
319
|
+
if (!this.incomingConnectionIsEmpty(this.runExecutionData.resultData.runData, workflow.connectionsByDestinationNode[inputData.node]["main"][0], runIndex)) {
|
|
306
320
|
continue;
|
|
307
321
|
}
|
|
308
322
|
}
|
|
@@ -313,20 +327,22 @@ class WorkflowExecute {
|
|
|
313
327
|
continue;
|
|
314
328
|
}
|
|
315
329
|
// Check if node got processed already
|
|
316
|
-
if (this.runExecutionData.resultData.runData[inputData.node] !==
|
|
330
|
+
if (this.runExecutionData.resultData.runData[inputData.node] !==
|
|
331
|
+
undefined) {
|
|
317
332
|
// Node got processed already so no need to add it
|
|
318
333
|
continue;
|
|
319
334
|
}
|
|
320
335
|
// Check if any of the parent nodes does not have any inputs. That
|
|
321
336
|
// would mean that it has to get added to the list of nodes to process.
|
|
322
|
-
const parentNodes = workflow.getParentNodes(inputData.node,
|
|
337
|
+
const parentNodes = workflow.getParentNodes(inputData.node, "main", -1);
|
|
323
338
|
let nodeToAdd = inputData.node;
|
|
324
339
|
parentNodes.push(inputData.node);
|
|
325
340
|
parentNodes.reverse();
|
|
326
341
|
for (const parentNode of parentNodes) {
|
|
327
342
|
// Check if that node is also an output connection of the
|
|
328
343
|
// previously processed one
|
|
329
|
-
if (inputData.node !== parentNode &&
|
|
344
|
+
if (inputData.node !== parentNode &&
|
|
345
|
+
checkOutputNodes.includes(parentNode)) {
|
|
330
346
|
// So the parent node will be added anyway which
|
|
331
347
|
// will then process this node next. So nothing to do.
|
|
332
348
|
nodeToAdd = undefined;
|
|
@@ -340,7 +356,8 @@ class WorkflowExecute {
|
|
|
340
356
|
break;
|
|
341
357
|
}
|
|
342
358
|
// Check if node got processed already
|
|
343
|
-
if (this.runExecutionData.resultData.runData[parentNode] !==
|
|
359
|
+
if (this.runExecutionData.resultData.runData[parentNode] !==
|
|
360
|
+
undefined) {
|
|
344
361
|
// Node got processed already so we can use the
|
|
345
362
|
// output data as input of this node
|
|
346
363
|
break;
|
|
@@ -364,7 +381,7 @@ class WorkflowExecute {
|
|
|
364
381
|
// Add empty item if the node does not have any input connections
|
|
365
382
|
addEmptyItem = true;
|
|
366
383
|
}
|
|
367
|
-
else if (this.incomingConnectionIsEmpty(this.runExecutionData.resultData.runData, workflow.connectionsByDestinationNode[nodeToAdd][
|
|
384
|
+
else if (this.incomingConnectionIsEmpty(this.runExecutionData.resultData.runData, workflow.connectionsByDestinationNode[nodeToAdd]["main"][0], runIndex)) {
|
|
368
385
|
// Add empty item also if the input data is empty
|
|
369
386
|
addEmptyItem = true;
|
|
370
387
|
}
|
|
@@ -402,10 +419,9 @@ class WorkflowExecute {
|
|
|
402
419
|
}
|
|
403
420
|
if (stillDataMissing) {
|
|
404
421
|
// Additional data is needed to run node so add it to waiting
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
this.runExecutionData.executionData.waitingExecution[connectionData.node] = {};
|
|
422
|
+
assertSafeKey(connectionData.node);
|
|
423
|
+
if (!Object.hasOwn(this.runExecutionData.executionData.waitingExecution, connectionData.node)) {
|
|
424
|
+
this.runExecutionData.executionData.waitingExecution[connectionData.node] = Object.create(null);
|
|
409
425
|
}
|
|
410
426
|
this.runExecutionData.executionData.waitingExecution[connectionData.node][runIndex] = {
|
|
411
427
|
main: connectionDataArray,
|
|
@@ -433,17 +449,20 @@ class WorkflowExecute {
|
|
|
433
449
|
// active executions anymore
|
|
434
450
|
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
435
451
|
processRunExecutionData(workflow) {
|
|
436
|
-
workflow_1.LoggerProxy.verbose(
|
|
437
|
-
console.log(`Workflow execution started: ID: ${workflow.id} - Name: ${workflow.name} - Active: ${workflow.active ?
|
|
452
|
+
workflow_1.LoggerProxy.verbose("Workflow execution started", { workflowId: workflow.id });
|
|
453
|
+
console.log(`Workflow execution started: ID: ${workflow.id} - Name: ${workflow.name} - Active: ${workflow.active ? "active" : "inactive"}`);
|
|
438
454
|
const startedAt = new Date();
|
|
439
455
|
const startNode = this.runExecutionData.executionData.nodeExecutionStack[0].node.name;
|
|
440
456
|
let destinationNode;
|
|
441
|
-
if (this.runExecutionData.startData
|
|
457
|
+
if (this.runExecutionData.startData?.destinationNode) {
|
|
442
458
|
destinationNode = this.runExecutionData.startData.destinationNode;
|
|
443
459
|
}
|
|
444
|
-
const workflowIssues = workflow.checkReadyForExecution({
|
|
460
|
+
const workflowIssues = workflow.checkReadyForExecution({
|
|
461
|
+
startNode,
|
|
462
|
+
destinationNode,
|
|
463
|
+
});
|
|
445
464
|
if (workflowIssues !== null) {
|
|
446
|
-
throw new Error(
|
|
465
|
+
throw new Error("The workflow has issues and can for that reason not be executed. Please fix them first.");
|
|
447
466
|
}
|
|
448
467
|
// Variables which hold temporary data for each node-execution
|
|
449
468
|
let executionData;
|
|
@@ -457,38 +476,44 @@ class WorkflowExecute {
|
|
|
457
476
|
this.runExecutionData.startData = {};
|
|
458
477
|
}
|
|
459
478
|
if (this.runExecutionData.waitTill) {
|
|
460
|
-
const lastNodeExecuted = this.runExecutionData.resultData
|
|
461
|
-
|
|
479
|
+
const lastNodeExecuted = this.runExecutionData.resultData
|
|
480
|
+
.lastNodeExecuted;
|
|
481
|
+
this.runExecutionData.executionData.nodeExecutionStack[0].node.disabled =
|
|
482
|
+
true;
|
|
462
483
|
this.runExecutionData.waitTill = undefined;
|
|
463
484
|
this.runExecutionData.resultData.runData[lastNodeExecuted].pop();
|
|
464
485
|
}
|
|
465
|
-
let currentExecutionTry =
|
|
466
|
-
let lastExecutionTry =
|
|
467
|
-
return new
|
|
486
|
+
let currentExecutionTry = "";
|
|
487
|
+
let lastExecutionTry = "";
|
|
488
|
+
return new p_cancelable_1.default((resolve, _reject, onCancel) => {
|
|
468
489
|
let gotCancel = false;
|
|
469
490
|
onCancel.shouldReject = false;
|
|
470
491
|
onCancel(() => {
|
|
471
492
|
gotCancel = true;
|
|
472
493
|
});
|
|
473
|
-
const returnPromise = (() =>
|
|
474
|
-
var _a, _b, _c, _d, _e;
|
|
494
|
+
const returnPromise = (async () => {
|
|
475
495
|
try {
|
|
476
|
-
|
|
496
|
+
await this.executeHook("workflowExecuteBefore", [workflow]);
|
|
477
497
|
}
|
|
478
498
|
catch (error) {
|
|
479
499
|
// Set the error that it can be saved correctly
|
|
480
|
-
executionError =
|
|
500
|
+
executionError = {
|
|
501
|
+
...error,
|
|
502
|
+
message: error.message,
|
|
503
|
+
stack: error.stack,
|
|
504
|
+
};
|
|
481
505
|
// Set the incoming data of the node that it can be saved correctly
|
|
482
506
|
// eslint-disable-next-line prefer-destructuring
|
|
483
|
-
executionData =
|
|
507
|
+
executionData =
|
|
508
|
+
this.runExecutionData.executionData.nodeExecutionStack[0];
|
|
484
509
|
this.runExecutionData.resultData = {
|
|
485
510
|
runData: {
|
|
486
511
|
[executionData.node.name]: [
|
|
487
512
|
{
|
|
488
513
|
startTime,
|
|
489
|
-
executionTime:
|
|
514
|
+
executionTime: Date.now() - startTime,
|
|
490
515
|
data: {
|
|
491
|
-
main: executionData.data[
|
|
516
|
+
main: executionData.data["main"],
|
|
492
517
|
},
|
|
493
518
|
},
|
|
494
519
|
],
|
|
@@ -515,16 +540,17 @@ class WorkflowExecute {
|
|
|
515
540
|
node: executionNode.name,
|
|
516
541
|
workflowId: workflow.id,
|
|
517
542
|
});
|
|
518
|
-
|
|
543
|
+
await this.executeHook("nodeExecuteBefore", [executionNode.name]);
|
|
519
544
|
// Get the index of the current run
|
|
520
545
|
runIndex = 0;
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
546
|
+
if (Object.hasOwn(this.runExecutionData.resultData.runData, executionNode.name)) {
|
|
547
|
+
runIndex =
|
|
548
|
+
this.runExecutionData.resultData.runData[executionNode.name]
|
|
549
|
+
.length;
|
|
524
550
|
}
|
|
525
551
|
currentExecutionTry = `${executionNode.name}:${runIndex}`;
|
|
526
552
|
if (currentExecutionTry === lastExecutionTry) {
|
|
527
|
-
throw new Error(
|
|
553
|
+
throw new Error("Did stop execution because execution seems to be in endless loop.");
|
|
528
554
|
}
|
|
529
555
|
if (this.runExecutionData.startData.runNodeFilter !== undefined &&
|
|
530
556
|
this.runExecutionData.startData.runNodeFilter.indexOf(executionNode.name) === -1) {
|
|
@@ -534,21 +560,22 @@ class WorkflowExecute {
|
|
|
534
560
|
continue;
|
|
535
561
|
}
|
|
536
562
|
// Check if all the data which is needed to run the node is available
|
|
537
|
-
if (Object.
|
|
563
|
+
if (Object.hasOwn(workflow.connectionsByDestinationNode, executionNode.name)) {
|
|
538
564
|
// Check if the node has incoming connections
|
|
539
|
-
if (Object.
|
|
565
|
+
if (Object.hasOwn(workflow.connectionsByDestinationNode[executionNode.name], "main")) {
|
|
540
566
|
let inputConnections;
|
|
541
567
|
let connectionIndex;
|
|
542
568
|
// eslint-disable-next-line prefer-const
|
|
543
|
-
inputConnections =
|
|
569
|
+
inputConnections =
|
|
570
|
+
workflow.connectionsByDestinationNode[executionNode.name]["main"];
|
|
544
571
|
for (connectionIndex = 0; connectionIndex < inputConnections.length; connectionIndex++) {
|
|
545
|
-
if (workflow.getHighestNode(executionNode.name,
|
|
572
|
+
if (workflow.getHighestNode(executionNode.name, "main", connectionIndex).length === 0) {
|
|
546
573
|
// If there is no valid incoming node (if all are disabled)
|
|
547
574
|
// then ignore that it has inputs and simply execute it as it is without
|
|
548
575
|
// any data
|
|
549
576
|
continue;
|
|
550
577
|
}
|
|
551
|
-
if (!Object.
|
|
578
|
+
if (!Object.hasOwn(executionData.data, "main")) {
|
|
552
579
|
// ExecutionData does not even have the connection set up so can
|
|
553
580
|
// not have that data, so add it again to be executed later
|
|
554
581
|
this.runExecutionData.executionData.nodeExecutionStack.push(executionData);
|
|
@@ -558,8 +585,8 @@ class WorkflowExecute {
|
|
|
558
585
|
// Check if it has the data for all the inputs
|
|
559
586
|
// The most nodes just have one but merge node for example has two and data
|
|
560
587
|
// of both inputs has to be available to be able to process the node.
|
|
561
|
-
if (executionData.data[
|
|
562
|
-
executionData.data[
|
|
588
|
+
if (executionData.data["main"].length < connectionIndex ||
|
|
589
|
+
executionData.data["main"][connectionIndex] === null) {
|
|
563
590
|
// Does not have the data of the connections so add back to stack
|
|
564
591
|
this.runExecutionData.executionData.nodeExecutionStack.push(executionData);
|
|
565
592
|
lastExecutionTry = currentExecutionTry;
|
|
@@ -571,7 +598,7 @@ class WorkflowExecute {
|
|
|
571
598
|
// Clone input data that nodes can not mess up data of parallel nodes which receive the same data
|
|
572
599
|
// TODO: Should only clone if multiple nodes get the same data or when it gets returned to frontned
|
|
573
600
|
// is very slow so only do if needed
|
|
574
|
-
startTime =
|
|
601
|
+
startTime = Date.now();
|
|
575
602
|
let maxTries = 1;
|
|
576
603
|
if (executionData.node.retryOnFail === true) {
|
|
577
604
|
// TODO: Remove the hardcoded default-values here and also in NodeSettings.vue
|
|
@@ -594,7 +621,7 @@ class WorkflowExecute {
|
|
|
594
621
|
// TODO: Improve that in the future and check if other nodes can
|
|
595
622
|
// be executed in the meantime
|
|
596
623
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
597
|
-
|
|
624
|
+
await new Promise((resolve) => {
|
|
598
625
|
setTimeout(() => {
|
|
599
626
|
resolve(undefined);
|
|
600
627
|
}, waitBetweenTries);
|
|
@@ -605,7 +632,7 @@ class WorkflowExecute {
|
|
|
605
632
|
node: executionNode.name,
|
|
606
633
|
workflowId: workflow.id,
|
|
607
634
|
});
|
|
608
|
-
nodeSuccessData =
|
|
635
|
+
nodeSuccessData = await workflow.runNode(executionData.node, executionData.data, this.runExecutionData, runIndex, this.additionalData, __1.NodeExecuteFunctions, this.mode);
|
|
609
636
|
workflow_1.LoggerProxy.debug(`Running node "${executionNode.name}" finished successfully`, {
|
|
610
637
|
node: executionNode.name,
|
|
611
638
|
workflowId: workflow.id,
|
|
@@ -615,9 +642,11 @@ class WorkflowExecute {
|
|
|
615
642
|
nodeSuccessData = null;
|
|
616
643
|
}
|
|
617
644
|
else {
|
|
618
|
-
this.runExecutionData.resultData.lastNodeExecuted =
|
|
645
|
+
this.runExecutionData.resultData.lastNodeExecuted =
|
|
646
|
+
executionData.node.name;
|
|
619
647
|
}
|
|
620
|
-
if (nodeSuccessData === null ||
|
|
648
|
+
if (nodeSuccessData === null ||
|
|
649
|
+
nodeSuccessData[0][0] === undefined) {
|
|
621
650
|
if (executionData.node.alwaysOutputData === true) {
|
|
622
651
|
nodeSuccessData = nodeSuccessData || [];
|
|
623
652
|
nodeSuccessData[0] = [
|
|
@@ -627,7 +656,8 @@ class WorkflowExecute {
|
|
|
627
656
|
];
|
|
628
657
|
}
|
|
629
658
|
}
|
|
630
|
-
if (nodeSuccessData === null &&
|
|
659
|
+
if (nodeSuccessData === null &&
|
|
660
|
+
!this.runExecutionData.waitTill) {
|
|
631
661
|
// If null gets returned it means that the node did succeed
|
|
632
662
|
// but did not have any data. So the branch should end
|
|
633
663
|
// (meaning the nodes afterwards should not be processed)
|
|
@@ -636,21 +666,27 @@ class WorkflowExecute {
|
|
|
636
666
|
break;
|
|
637
667
|
}
|
|
638
668
|
catch (error) {
|
|
639
|
-
this.runExecutionData.resultData.lastNodeExecuted =
|
|
640
|
-
|
|
669
|
+
this.runExecutionData.resultData.lastNodeExecuted =
|
|
670
|
+
executionData.node.name;
|
|
671
|
+
const err = error;
|
|
672
|
+
executionError = {
|
|
673
|
+
...err,
|
|
674
|
+
message: err.message,
|
|
675
|
+
stack: err.stack,
|
|
676
|
+
};
|
|
641
677
|
// Check if it's a critical database connection error that should fail immediately
|
|
642
|
-
const isCriticalConnectionError =
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
678
|
+
const isCriticalConnectionError = err.message?.includes("too many clients") ||
|
|
679
|
+
err.message?.includes("Connection terminated") ||
|
|
680
|
+
err.message?.includes("connection is closed") ||
|
|
681
|
+
err.message?.includes("ECONNRESET") ||
|
|
682
|
+
err.message?.includes("ENOTFOUND") ||
|
|
683
|
+
err.code === "ECONNRESET" ||
|
|
684
|
+
err.code === "ENOTFOUND";
|
|
649
685
|
if (isCriticalConnectionError) {
|
|
650
|
-
workflow_1.LoggerProxy.error(`Critical database connection error in node "${executionNode.name}": ${
|
|
686
|
+
workflow_1.LoggerProxy.error(`Critical database connection error in node "${executionNode.name}": ${err.message}`, {
|
|
651
687
|
node: executionNode.name,
|
|
652
688
|
workflowId: workflow.id,
|
|
653
|
-
error:
|
|
689
|
+
error: err.message,
|
|
654
690
|
});
|
|
655
691
|
// For critical connection errors, break out of retry loop immediately
|
|
656
692
|
// This will cause the workflow to fail on this node
|
|
@@ -664,22 +700,24 @@ class WorkflowExecute {
|
|
|
664
700
|
}
|
|
665
701
|
// Add the data to return to the user
|
|
666
702
|
// (currently does not get cloned as data does not get changed, maybe later we should do that?!?!)
|
|
667
|
-
|
|
703
|
+
assertSafeKey(executionNode.name);
|
|
704
|
+
if (!Object.hasOwn(this.runExecutionData.resultData.runData, executionNode.name)) {
|
|
668
705
|
this.runExecutionData.resultData.runData[executionNode.name] = [];
|
|
669
706
|
}
|
|
670
707
|
taskData = {
|
|
671
708
|
startTime,
|
|
672
|
-
executionTime:
|
|
709
|
+
executionTime: Date.now() - startTime,
|
|
673
710
|
};
|
|
674
711
|
if (executionError !== undefined) {
|
|
675
712
|
taskData.error = executionError;
|
|
676
713
|
if (executionData.node.continueOnFail === true) {
|
|
677
714
|
// Workflow should continue running even if node errors
|
|
678
|
-
if (Object.
|
|
715
|
+
if (Object.hasOwn(executionData.data, "main") &&
|
|
716
|
+
executionData.data["main"].length > 0) {
|
|
679
717
|
// Simply get the input data of the node if it has any and pass it through
|
|
680
718
|
// to the next node
|
|
681
|
-
if (executionData.data[
|
|
682
|
-
nodeSuccessData = [executionData.data[
|
|
719
|
+
if (executionData.data["main"][0] !== null) {
|
|
720
|
+
nodeSuccessData = [executionData.data["main"][0]];
|
|
683
721
|
}
|
|
684
722
|
}
|
|
685
723
|
}
|
|
@@ -688,7 +726,7 @@ class WorkflowExecute {
|
|
|
688
726
|
this.runExecutionData.resultData.runData[executionNode.name].push(taskData);
|
|
689
727
|
// Add the execution data again so that it can get restarted
|
|
690
728
|
this.runExecutionData.executionData.nodeExecutionStack.unshift(executionData);
|
|
691
|
-
|
|
729
|
+
await this.executeHook("nodeExecuteAfter", [
|
|
692
730
|
executionNode.name,
|
|
693
731
|
taskData,
|
|
694
732
|
this.runExecutionData,
|
|
@@ -702,11 +740,11 @@ class WorkflowExecute {
|
|
|
702
740
|
for (const execution of nodeSuccessData) {
|
|
703
741
|
for (const lineResult of execution) {
|
|
704
742
|
if (lineResult.json !== undefined &&
|
|
705
|
-
lineResult.json[
|
|
706
|
-
lineResult.json[
|
|
707
|
-
lineResult.error = lineResult.json[
|
|
743
|
+
lineResult.json["$error"] !== undefined &&
|
|
744
|
+
lineResult.json["$error"] !== undefined) {
|
|
745
|
+
lineResult.error = lineResult.json["$error"];
|
|
708
746
|
lineResult.json = {
|
|
709
|
-
error: lineResult.json[
|
|
747
|
+
error: lineResult.json["$error"].message,
|
|
710
748
|
};
|
|
711
749
|
}
|
|
712
750
|
else if (lineResult.error !== undefined) {
|
|
@@ -720,7 +758,7 @@ class WorkflowExecute {
|
|
|
720
758
|
};
|
|
721
759
|
this.runExecutionData.resultData.runData[executionNode.name].push(taskData);
|
|
722
760
|
if (this.runExecutionData.waitTill) {
|
|
723
|
-
|
|
761
|
+
await this.executeHook("nodeExecuteAfter", [
|
|
724
762
|
executionNode.name,
|
|
725
763
|
taskData,
|
|
726
764
|
this.runExecutionData,
|
|
@@ -729,12 +767,12 @@ class WorkflowExecute {
|
|
|
729
767
|
this.runExecutionData.executionData.nodeExecutionStack.unshift(executionData);
|
|
730
768
|
break;
|
|
731
769
|
}
|
|
732
|
-
if (this.runExecutionData.startData &&
|
|
733
|
-
this.runExecutionData.startData.destinationNode
|
|
734
|
-
|
|
770
|
+
if (this.runExecutionData.startData?.destinationNode &&
|
|
771
|
+
this.runExecutionData.startData.destinationNode ===
|
|
772
|
+
executionNode.name) {
|
|
735
773
|
// Before stopping, make sure we are executing hooks so
|
|
736
774
|
// That frontend is notified for example for manual executions.
|
|
737
|
-
|
|
775
|
+
await this.executeHook("nodeExecuteAfter", [
|
|
738
776
|
executionNode.name,
|
|
739
777
|
taskData,
|
|
740
778
|
this.runExecutionData,
|
|
@@ -744,26 +782,27 @@ class WorkflowExecute {
|
|
|
744
782
|
}
|
|
745
783
|
// Add the nodes to which the current node has an output connection to that they can
|
|
746
784
|
// be executed next
|
|
747
|
-
if (Object.
|
|
748
|
-
if (Object.
|
|
785
|
+
if (Object.hasOwn(workflow.connectionsBySourceNode, executionNode.name)) {
|
|
786
|
+
if (Object.hasOwn(workflow.connectionsBySourceNode[executionNode.name], "main")) {
|
|
749
787
|
let outputIndex;
|
|
750
788
|
let connectionData;
|
|
751
789
|
// Iterate over all the outputs
|
|
752
790
|
// Add the nodes to be executed
|
|
753
791
|
// eslint-disable-next-line @typescript-eslint/no-for-in-array
|
|
754
|
-
for (outputIndex in workflow.connectionsBySourceNode[executionNode.name][
|
|
755
|
-
if (!Object.
|
|
792
|
+
for (outputIndex in workflow.connectionsBySourceNode[executionNode.name]["main"]) {
|
|
793
|
+
if (!Object.hasOwn(workflow.connectionsBySourceNode[executionNode.name]["main"], outputIndex)) {
|
|
756
794
|
continue;
|
|
757
795
|
}
|
|
758
796
|
// Iterate over all the different connections of this output
|
|
759
|
-
for (connectionData of workflow.connectionsBySourceNode[executionNode.name][
|
|
760
|
-
if (!Object.
|
|
797
|
+
for (connectionData of workflow.connectionsBySourceNode[executionNode.name]["main"][outputIndex]) {
|
|
798
|
+
if (!Object.hasOwn(workflow.nodes, connectionData.node)) {
|
|
761
799
|
return Promise.reject(new Error(`The node "${executionNode.name}" connects to not found node "${connectionData.node}"`));
|
|
762
800
|
}
|
|
763
|
-
if (nodeSuccessData[outputIndex] &&
|
|
764
|
-
(nodeSuccessData[outputIndex].length !== 0 ||
|
|
801
|
+
if (nodeSuccessData[Number(outputIndex)] &&
|
|
802
|
+
(nodeSuccessData[Number(outputIndex)].length !== 0 ||
|
|
803
|
+
connectionData.index > 0)) {
|
|
765
804
|
// Add the node only if it did execute or if connected to second "optional" input
|
|
766
|
-
this.addNodeToBeExecuted(workflow, connectionData, parseInt(outputIndex, 10), executionNode.name, nodeSuccessData, runIndex);
|
|
805
|
+
this.addNodeToBeExecuted(workflow, connectionData, Number.parseInt(outputIndex, 10), executionNode.name, nodeSuccessData, runIndex);
|
|
767
806
|
}
|
|
768
807
|
}
|
|
769
808
|
}
|
|
@@ -773,72 +812,86 @@ class WorkflowExecute {
|
|
|
773
812
|
// Execute hooks now to make sure that all hooks are executed properly
|
|
774
813
|
// Await is needed to make sure that we don't fall into concurrency problems
|
|
775
814
|
// When saving node execution data
|
|
776
|
-
|
|
815
|
+
await this.executeHook("nodeExecuteAfter", [
|
|
777
816
|
executionNode.name,
|
|
778
817
|
taskData,
|
|
779
818
|
this.runExecutionData,
|
|
780
819
|
]);
|
|
781
820
|
}
|
|
782
821
|
return Promise.resolve();
|
|
783
|
-
})
|
|
784
|
-
.then(() =>
|
|
822
|
+
})()
|
|
823
|
+
.then(async () => {
|
|
785
824
|
if (gotCancel && executionError === undefined) {
|
|
786
|
-
return this.processSuccessExecution(startedAt, workflow, new workflow_1.WorkflowOperationError(
|
|
825
|
+
return this.processSuccessExecution(startedAt, workflow, new workflow_1.WorkflowOperationError("Workflow has been canceled or timed out!"));
|
|
787
826
|
}
|
|
788
827
|
return this.processSuccessExecution(startedAt, workflow, executionError);
|
|
789
|
-
})
|
|
790
|
-
.catch((error) =>
|
|
828
|
+
})
|
|
829
|
+
.catch(async (error) => {
|
|
791
830
|
const fullRunData = this.getFullRunData(startedAt);
|
|
792
|
-
fullRunData.data.resultData.error =
|
|
831
|
+
fullRunData.data.resultData.error = {
|
|
832
|
+
...error,
|
|
833
|
+
message: error.message,
|
|
834
|
+
stack: error.stack,
|
|
835
|
+
};
|
|
793
836
|
// Check if static data changed
|
|
794
837
|
let newStaticData;
|
|
795
838
|
// eslint-disable-next-line no-underscore-dangle
|
|
796
|
-
if (workflow.staticData[
|
|
839
|
+
if (workflow.staticData["__dataChanged"] === true) {
|
|
797
840
|
// Static data of workflow changed
|
|
798
841
|
newStaticData = workflow.staticData;
|
|
799
842
|
}
|
|
800
|
-
|
|
843
|
+
await this.executeHook("workflowExecuteAfter", [
|
|
844
|
+
fullRunData,
|
|
845
|
+
newStaticData,
|
|
846
|
+
]).catch(
|
|
801
847
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
802
848
|
(error) => {
|
|
803
849
|
// eslint-disable-next-line no-console
|
|
804
850
|
console.error('There was a problem running hook "workflowExecuteAfter"', error);
|
|
805
851
|
});
|
|
806
852
|
return fullRunData;
|
|
807
|
-
})
|
|
853
|
+
});
|
|
808
854
|
return returnPromise.then(resolve);
|
|
809
855
|
});
|
|
810
856
|
}
|
|
811
|
-
processSuccessExecution(startedAt, workflow, executionError) {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
857
|
+
async processSuccessExecution(startedAt, workflow, executionError) {
|
|
858
|
+
const fullRunData = this.getFullRunData(startedAt);
|
|
859
|
+
if (executionError !== undefined) {
|
|
860
|
+
workflow_1.LoggerProxy.verbose("Workflow execution finished with error", {
|
|
861
|
+
error: executionError,
|
|
862
|
+
workflowId: workflow.id,
|
|
863
|
+
});
|
|
864
|
+
fullRunData.data.resultData.error = {
|
|
865
|
+
...executionError,
|
|
866
|
+
message: executionError.message,
|
|
867
|
+
stack: executionError.stack,
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
else if (this.runExecutionData.waitTill) {
|
|
871
|
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
872
|
+
workflow_1.LoggerProxy.verbose(`Workflow execution will wait until ${this.runExecutionData.waitTill}`, {
|
|
873
|
+
workflowId: workflow.id,
|
|
874
|
+
});
|
|
875
|
+
fullRunData.waitTill = this.runExecutionData.waitTill;
|
|
876
|
+
}
|
|
877
|
+
else {
|
|
878
|
+
workflow_1.LoggerProxy.verbose("Workflow execution finished successfully", {
|
|
879
|
+
workflowId: workflow.id,
|
|
880
|
+
});
|
|
881
|
+
fullRunData.finished = true;
|
|
882
|
+
}
|
|
883
|
+
// Check if static data changed
|
|
884
|
+
let newStaticData;
|
|
885
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
886
|
+
if (workflow.staticData["__dataChanged"] === true) {
|
|
887
|
+
// Static data of workflow changed
|
|
888
|
+
newStaticData = workflow.staticData;
|
|
889
|
+
}
|
|
890
|
+
await this.executeHook("workflowExecuteAfter", [
|
|
891
|
+
fullRunData,
|
|
892
|
+
newStaticData,
|
|
893
|
+
]);
|
|
894
|
+
return fullRunData;
|
|
842
895
|
}
|
|
843
896
|
getFullRunData(startedAt) {
|
|
844
897
|
const fullRunData = {
|
|
@@ -851,4 +904,3 @@ class WorkflowExecute {
|
|
|
851
904
|
}
|
|
852
905
|
}
|
|
853
906
|
exports.WorkflowExecute = WorkflowExecute;
|
|
854
|
-
//# sourceMappingURL=WorkflowExecute.js.map
|