@5minds/node-red-contrib-processcube 1.16.1-develop-c6444b-mhvwu80i → 1.16.1-develop-48cf80-mhvyy20p

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.
@@ -1,9 +1,110 @@
1
1
  const EventEmitter = require('node:events');
2
2
 
3
+ class ExternalTaskNodeStates {
4
+ constructor(flowNodeInstanceId) {
5
+ this.flowNodeInstanceId = flowNodeInstanceId;
6
+ this.nodeStades = {}; // Track send calls per nodeId
7
+ }
8
+
9
+ markSended(nodeId) {
10
+ if (!this.nodeStades[nodeId]) {
11
+ this.nodeStades[nodeId] = { gotSend: false, gotCompleted: false };
12
+ }
13
+
14
+ this.nodeStades[nodeId].gotSend = true;
15
+ }
16
+
17
+ markCompleted(nodeId) {
18
+ if (!this.nodeStades[nodeId]) {
19
+ this.nodeStades[nodeId] = { gotSend: false, gotCompleted: false };
20
+ }
21
+
22
+ this.nodeStades[nodeId].gotCompleted = true;
23
+ }
24
+
25
+ checkIfCompletedWithoutSend(nodeId) {
26
+ const nodeState = this.nodeStades[nodeId];
27
+ const result = (nodeState && nodeState.gotCompleted && !nodeState.gotSend);
28
+
29
+ return result;
30
+ }
31
+ }
32
+
3
33
  module.exports = function (RED) {
4
34
 
5
35
  const os = require('os');
6
36
 
37
+ // Global dictionary for tracking external tasks by flowNodeInstanceId
38
+ const globalExternalTaskStates = {};
39
+
40
+ const raiseExternalTaskError = (flowNodeInstanceId, etwInputNodeId, nodeId) => {
41
+ const fullNode = RED.nodes.getNode(nodeId);
42
+
43
+ const wires = fullNode?.wires;
44
+ const hasConnectedOutputs = wires && wires.some(wireArray => wireArray && wireArray.length > 0);
45
+
46
+ if (hasConnectedOutputs) {
47
+ const inputNode = RED.nodes.getNode(etwInputNodeId);
48
+
49
+ if (inputNode && inputNode.eventEmitter) {
50
+ const errorMessage = `Node ${nodeId} (${fullNode.name || fullNode.type}) completed without sending output`;
51
+ const error = new Error(errorMessage);
52
+ error.errorCode = 'NODE_NO_OUTPUT';
53
+ error.errorDetails = RED.util.encodeObject({
54
+ flowNodeInstanceId: flowNodeInstanceId,
55
+ nodeId: nodeId,
56
+ nodeName: fullNode.name,
57
+ nodeType: fullNode.type
58
+ });
59
+
60
+ inputNode.eventEmitter.emit(`handle-${flowNodeInstanceId}`, error, true);
61
+ }
62
+ }
63
+ };
64
+
65
+ // Example synchronous onSend hook
66
+ RED.hooks.add("onSend", (sendEvents) => {
67
+ for (const sendEvent of sendEvents) {
68
+
69
+ // Call send method on ExternalTaskState if this message has a flowNodeInstanceId
70
+ if (sendEvent.msg?.flowNodeInstanceId) {
71
+ let externalTaskNodeStates = globalExternalTaskStates[sendEvent.msg.flowNodeInstanceId];
72
+
73
+ if (!externalTaskNodeStates) {
74
+ externalTaskNodeStates = new ExternalTaskNodeStates(sendEvent.msg.flowNodeInstanceId);
75
+ globalExternalTaskStates[sendEvent.msg.flowNodeInstanceId] = externalTaskNodeStates;
76
+ }
77
+
78
+ externalTaskNodeStates.markSended(sendEvent.source.node.id)
79
+
80
+ if (externalTaskNodeStates.checkIfCompletedWithoutSend(sendEvent.source.node.id)) {
81
+ raiseExternalTaskError(sendEvent.msg.flowNodeInstanceId, sendEvent.msg.etw_input_node_id, sendEvent.source.node.id);
82
+ }
83
+ }
84
+ }
85
+ });
86
+
87
+ const onCompleted = (completeEvent) => {
88
+
89
+ // Check if this is an external task message
90
+ if (completeEvent.msg?.flowNodeInstanceId) {
91
+ let externalTaskNodeStates = globalExternalTaskStates[completeEvent.msg.flowNodeInstanceId];
92
+
93
+ if (!externalTaskNodeStates) {
94
+ externalTaskNodeStates = new ExternalTaskNodeStates(completeEvent.msg.flowNodeInstanceId);
95
+ globalExternalTaskStates[completeEvent.msg.flowNodeInstanceId] = externalTaskNodeStates;
96
+ }
97
+
98
+ externalTaskNodeStates.markCompleted(completeEvent.node.id);
99
+
100
+ if (externalTaskNodeStates.checkIfCompletedWithoutSend(completeEvent.node.id)) {
101
+ raiseExternalTaskError(completeEvent.msg.flowNodeInstanceId, completeEvent.msg.etw_input_node_id, completeEvent.node.id);
102
+ }
103
+ }
104
+ }
105
+
106
+ RED.hooks.add("onComplete", onCompleted);
107
+
7
108
  function ExternalTaskInput(config) {
8
109
  RED.nodes.createNode(this, config);
9
110
  var node = this;
@@ -357,15 +458,30 @@ module.exports = function (RED) {
357
458
  return;
358
459
  }
359
460
  const etwCallback = async (payload, externalTask) => {
461
+
462
+ globalExternalTaskStates[externalTask.flowNodeInstanceId] = new ExternalTaskNodeStates(externalTask.flowNodeInstanceId);
463
+
360
464
  const saveHandleCallback = (data, callback, msg) => {
361
465
  try {
362
466
  callback(data);
363
467
  node.log(`send to engine *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}', topic '${node.topic}' and *processInstanceId* ${externalTask.processInstanceId}`);
468
+
469
+ // Remove ExternalTaskState from global dictionary
470
+ if (globalExternalTaskStates[externalTask.flowNodeInstanceId]) {
471
+ delete globalExternalTaskStates[externalTask.flowNodeInstanceId];
472
+ }
473
+
364
474
  node.setFinishHandlingTaskStatus(externalTask);
365
475
  } catch (error) {
476
+ // Remove ExternalTaskState from global dictionary on error as well
477
+ if (globalExternalTaskStates[externalTask.flowNodeInstanceId]) {
478
+ delete globalExternalTaskStates[externalTask.flowNodeInstanceId];
479
+ }
480
+
366
481
  node.setErrorFinishHandlingTaskStatus(externalTask, error);
367
482
  msg.error = error;
368
483
  node.error(`failed send to engine *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}', topic '${node.topic}' and *processInstanceId* ${externalTask.processInstanceId}: ${error?.message}`, msg);
484
+ callback(error);
369
485
  }
370
486
  };
371
487
 
@@ -405,7 +521,7 @@ module.exports = function (RED) {
405
521
  msg.etw_duration = new Date(msg.etw_finished_at) - new Date(msg.etw_started_at);
406
522
  }
407
523
  } catch (error) {
408
- node.error(`failed to calculate duration: ${error?.message}`, msg);
524
+ node.error(`failed to calculate duration: ${error?.message}`, msg);
409
525
  }
410
526
 
411
527
  node.log(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@5minds/node-red-contrib-processcube",
3
- "version": "1.16.1-develop-c6444b-mhvwu80i",
3
+ "version": "1.16.1-develop-48cf80-mhvyy20p",
4
4
  "license": "MIT",
5
5
  "description": "Node-RED nodes for ProcessCube",
6
6
  "scripts": {