@5minds/node-red-contrib-processcube 0.15.0-error-handling-in-process-instance-query-and-add-prettier-6b3dae-lz096tqk → 0.15.0-fix-error-in-process-instance-query-f9f0d2-lz03zzg4

Sign up to get free protection for your applications and to get access to all the features.
package/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM node:20 AS builder
1
+ FROM node:20 as builder
2
2
 
3
3
  COPY ./ /src/node-red-contrib-processcube
4
4
 
@@ -5,17 +5,12 @@ services:
5
5
  context: .
6
6
  ports:
7
7
  - "1880:1880"
8
- - "9229:9229"
9
8
  environment:
10
9
  - TZ=Europe/Berlin
11
10
  - ENGINE_URL=http://engine:8000
12
11
  - FLOWS=/nodered/node-red-contrib-processcube-flows.json
13
12
  volumes:
14
13
  - ./nodered/:/nodered/
15
- - ./examples/:/examples/
16
- depends_on:
17
- - engine
18
- - authority
19
14
 
20
15
  engine:
21
16
  image: 5minds/processcube_engine:2024-1
@@ -24,16 +19,9 @@ services:
24
19
  volumes:
25
20
  - ./processes:/processes:ro
26
21
  environment:
27
- application__name: Engine for Node-RED contrib
28
22
  iam__baseUrl: http://authority:11560
29
23
  iam__allowAnonymousRootAccess: true
30
24
  command: --seed-dir=/processes --port 8000
31
- depends_on:
32
- - authority
33
- healthcheck:
34
- test: bash -c "[ -f /tmp/healthy ]"
35
- timeout: 1s
36
- retries: 20
37
25
 
38
26
  authority:
39
27
  image: 5minds/processcube_authority:3.0.4
@@ -26,20 +26,6 @@
26
26
  </div>
27
27
  </script>
28
28
 
29
- <script type="text/markdown" data-help-name="externaltask-error">
30
- Used for reporting errors in the processing of external tasks. The error
31
- code `Error` in the configuration is forwarded to the ProcessCube engine for
32
- handling within _Error-Boundary-Events_.
33
-
34
- ## Inputs
35
-
36
- : msg (Object) : Passed as `ErrorDetails` to the engine
37
- : Error (string) : From the configuration
38
- : Message (string) : The caught exception message
39
- : StackTrace (string) : The stack trace of the exception
40
-
41
- ### References
42
-
43
- - [The ProcessCube Developer Network](https://processcube.io) - All documentation for the ProcessCube&copy; platform
44
- - [Node-RED Integration in ProcessCube&copy;](https://processcube.io/docs/node-red) - Node-RED integration in ProcessCube&copy;
29
+ <script type="text/html" data-help-name="externaltask-error">
30
+ <p>A node which error response to an External Task of https://processcube.io</p>
45
31
  </script>
@@ -7,22 +7,24 @@ module.exports = function (RED) {
7
7
  var eventEmitter = flowContext.get('emitter');
8
8
 
9
9
  node.on('input', function (msg) {
10
- const flowNodeInstanceId = msg.flowNodeInstanceId;
10
+ const externalTaskId = msg.externalTaskId;
11
11
 
12
- let msgError = msg.error;
12
+ let error = msg.error;
13
13
 
14
- if (msgError === undefined) {
15
- msgError.message = 'An error occurred';
14
+ if (error === undefined) {
15
+ error.message = 'An error occurred';
16
+ error.source = msg.payload;
16
17
  }
17
18
 
18
- const error = new Error(msgError.message);
19
- error.errorCode = config.error;
20
- error.errorDetails = RED.util.encodeObject(msg);
19
+ msg.payload = {
20
+ error: {
21
+ errorCode: config.error,
22
+ errorMessage: error.message,
23
+ errorDetails: error.source,
24
+ },
25
+ };
21
26
 
22
- msg.errorCode = config.error;
23
- msg.errorMessage = msgError.message;
24
-
25
- eventEmitter.emit(`handle-${flowNodeInstanceId}`, error, true);
27
+ eventEmitter.emit(`error-${externalTaskId}`, msg.payload);
26
28
 
27
29
  node.send(msg);
28
30
  });
@@ -31,23 +31,6 @@
31
31
  </div>
32
32
  </script>
33
33
 
34
- <script type="text/markdown" data-help-name="externaltask-input">
35
- Waiting for external tasks that correspond to the `Topic` configured in
36
- the connected ProcessCube Engine for processing.
37
-
38
- ## Outputs
39
-
40
- : payload (string) : Defines the input of the external task token
41
- : task (object) : The external task object
42
- : flowNodeInstanceId : The Id of the external task, which is needed to complete the task
43
-
44
- ### Details
45
-
46
- - To finish the external task the `externaltask-output` node is required.
47
- - For handling a error while executing a flow as external task the `externaltask-error` node is required.
48
-
49
- ### References
50
-
51
- - [The ProcessCube Developer Network](https://processcube.io) - All documentation for the ProcessCube&copy; Plattform
52
- - [Node-RED Integration in ProcessCube&copy;](https://processcube.io/docs/node-red) - Node-RED Integration in ProcessCube&copy;
34
+ <script type="text/html" data-help-name="externaltask-input">
35
+ <p>A node which subscribes to an External Task Topic of https://processcube.io</p>
53
36
  </script>
@@ -1,24 +1,44 @@
1
+ const process = require('process');
1
2
  const EventEmitter = require('node:events');
2
3
 
4
+ const engine_client = require('@5minds/processcube_engine_client');
5
+
3
6
  function showStatus(node, msgCounter) {
4
7
  if (msgCounter >= 1) {
5
- node.status({ fill: 'blue', shape: 'dot', text: `handling tasks ${msgCounter}.` });
8
+ node.status({ fill: 'blue', shape: 'dot', text: `handling tasks ${msgCounter}` });
6
9
  } else {
7
- node.status({ fill: 'blue', shape: 'ring', text: `subcribed.` });
10
+ node.status({ fill: 'blue', shape: 'ring', text: `subcribed ${msgCounter}` });
8
11
  }
9
12
  }
10
13
 
11
- const started_external_tasks = {};
14
+ function decrCounter(msgCounter) {
15
+ msgCounter--;
16
+
17
+ if (msgCounter < 0) {
18
+ msgCounter = 0;
19
+ }
20
+
21
+ return msgCounter;
22
+ }
12
23
 
13
24
  module.exports = function (RED) {
14
25
  function ExternalTaskInput(config) {
15
26
  RED.nodes.createNode(this, config);
16
27
  var node = this;
28
+ var msgCounter = 0;
17
29
  var flowContext = node.context().flow;
30
+ var nodeContext = node.context();
18
31
 
19
32
  this.engine = this.server = RED.nodes.getNode(config.engine);
20
33
 
21
- const client = this.engine.getEngineClient();
34
+ const engineUrl = this.engine?.url || process.env.ENGINE_URL || 'http://engine:8000';
35
+
36
+ var client = nodeContext.get('client');
37
+
38
+ if (!client) {
39
+ nodeContext.set('client', new engine_client.EngineClient(engineUrl));
40
+ client = nodeContext.get('client');
41
+ }
22
42
 
23
43
  var eventEmitter = flowContext.get('emitter');
24
44
 
@@ -29,78 +49,33 @@ module.exports = function (RED) {
29
49
 
30
50
  client.externalTasks
31
51
  .subscribeToExternalTaskTopic(config.topic, async (payload, externalTask) => {
32
- const saveHandleCallback = (data, callback) => {
33
- try {
34
- callback(data);
35
- } catch (error) {
36
- node.error(`Error in callback 'saveHandleCallback': ${error.message}`);
37
- }
38
- };
52
+ msgCounter++;
39
53
 
40
54
  return await new Promise((resolve, reject) => {
41
- const handleFinishTask = (msg) => {
42
- let result = RED.util.encodeObject(msg.payload);
43
-
44
- node.log(
45
- `handle event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* ${externalTask.processInstanceId} with result ${result} on msg._msgid ${msg._msgid}.`,
46
- );
47
-
48
- if (externalTask.flowNodeInstanceId) {
49
- delete started_external_tasks[externalTask.flowNodeInstanceId];
50
- }
51
-
52
- showStatus(node, Object.keys(started_external_tasks).length);
53
-
54
- //resolve(result);
55
- saveHandleCallback(result, resolve);
56
- };
57
-
58
- const handleErrorTask = (msg) => {
59
- node.log(
60
- `handle error event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' on *msg._msgid* '${msg._msgid}'.`,
61
- );
62
-
63
- if (externalTask.flowNodeInstanceId) {
64
- delete started_external_tasks[externalTask.flowNodeInstanceId];
65
- }
66
-
67
- showStatus(node, Object.keys(started_external_tasks).length);
68
-
69
- // TODO: with reject, the default error handling is proceed
70
- // SEE: https://github.com/5minds/ProcessCube.Engine.Client.ts/blob/develop/src/ExternalTaskWorker.ts#L180
71
- // reject(result);
72
- //resolve(msg);
73
- saveHandleCallback(msg, resolve);
74
- };
75
-
76
- eventEmitter.once(`handle-${externalTask.flowNodeInstanceId}`, (msg, isError = false) => {
77
- node.log(
78
- `handle event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' with *msg._msgid* '${msg._msgid}' and *isError* '${isError}'`,
79
- );
80
-
81
- if (isError) {
82
- handleErrorTask(msg);
83
- } else {
84
- handleFinishTask(msg);
85
- }
55
+ // TODO: once ist 2x gebunden
56
+ eventEmitter.once(`finish-${externalTask.flowNodeInstanceId}`, (result) => {
57
+ msgCounter = decrCounter(msgCounter);
58
+
59
+ showStatus(node, msgCounter);
60
+ resolve(result);
86
61
  });
87
62
 
88
- started_external_tasks[externalTask.flowNodeInstanceId] = externalTask;
63
+ eventEmitter.once(`error-${externalTask.flowNodeInstanceId}`, (msg) => {
64
+ msgCounter = decrCounter(msgCounter);
65
+ showStatus(node, msgCounter);
89
66
 
90
- showStatus(node, Object.keys(started_external_tasks).length);
67
+ var result = msg.payload ? msg.payload : msg;
91
68
 
92
- let msg = {
93
- _msgid: RED.util.generateId(),
94
- task: RED.util.encodeObject(externalTask),
95
- payload: payload,
96
- flowNodeInstanceId: externalTask.flowNodeInstanceId,
97
- };
69
+ reject(result);
70
+ });
98
71
 
99
- node.log(
100
- `Received *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' with *msg._msgid* '${msg._msgid}'`,
101
- );
72
+ showStatus(node, msgCounter);
102
73
 
103
- node.send(msg);
74
+ node.send({
75
+ topic: externalTask.topic,
76
+ payload: payload,
77
+ externalTaskId: externalTask.flowNodeInstanceId,
78
+ });
104
79
  });
105
80
  })
106
81
  .then(async (externalTaskWorker) => {
@@ -110,47 +85,16 @@ module.exports = function (RED) {
110
85
  node.server.registerOnIdentityChanged((identity) => {
111
86
  externalTaskWorker.identity = identity;
112
87
  });
88
+ await externalTaskWorker.start();
113
89
 
114
- // export type WorkerErrorHandler = (errorType: 'fetchAndLock' | 'extendLock' | 'processExternalTask' | 'finishExternalTask', error: Error, externalTask?: ExternalTask<any>) => void;
115
- externalTaskWorker.onWorkerError((errorType, error, externalTask) => {
116
- switch (errorType) {
117
- case 'extendLock':
118
- case 'finishExternalTask':
119
- case 'processExternalTask':
120
- node.error(
121
- `Worker error ${errorType} for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}': ${error.message}`,
122
- );
123
-
124
- if (externalTask) {
125
- delete started_external_tasks[externalTask.flowNodeInstanceId];
126
- }
127
-
128
- showStatus(node, Object.keys(started_external_tasks).length);
129
- break;
130
- default:
131
- node.error(`Worker error ${errorType}: ${error.message}`);
132
- break;
133
- }
134
- });
135
-
136
- try {
137
- externalTaskWorker.start();
138
- } catch (error) {
139
- node.error(`Worker start 'externalTaskWorker.start' failed: ${error.message}`);
140
- }
141
-
142
- node.on('close', () => {
90
+ node.on('close', async () => {
143
91
  try {
144
92
  externalTaskWorker.stop();
145
93
  } catch {
146
- node.error('Client close failed');
94
+ console.warn('Client close failed');
147
95
  }
148
96
  });
149
- })
150
- .catch((error) => {
151
- node.error(`Error in subscribeToExternalTaskTopic: ${error.message}`);
152
97
  });
153
98
  }
154
-
155
99
  RED.nodes.registerType('externaltask-input', ExternalTaskInput);
156
100
  };
@@ -21,16 +21,6 @@
21
21
  </div>
22
22
  </script>
23
23
 
24
- <script type="text/markdown" data-help-name="externaltask-output">
25
- Used to complete the external task. The `msg.payload` is returned to the ProcessCube
26
- engine as the result of the external task.
27
-
28
- ## Inputs
29
-
30
- : payload (Object) : Returned to the ProcessCube engine as the result of the external task
31
-
32
- ### References
33
-
34
- - [The ProcessCube Developer Network](https://processcube.io) - All documentation for the ProcessCube&copy; platform
35
- - [Node-RED Integration in ProcessCube&copy;](https://processcube.io/docs/node-red) - Node-RED integration in ProcessCube&copy;
24
+ <script type="text/html" data-help-name="externaltask-output">
25
+ <p>A node which response to an External Task of https://processcube.io</p>
36
26
  </script>
@@ -7,13 +7,13 @@ module.exports = function (RED) {
7
7
  var eventEmitter = flowContext.get('emitter');
8
8
 
9
9
  node.on('input', function (msg) {
10
- const flowNodeInstanceId = msg.flowNodeInstanceId;
10
+ const externalTaskId = msg.externalTaskId;
11
11
 
12
- if (!flowNodeInstanceId) {
12
+ if (!externalTaskId) {
13
13
  node.error('Error: The message did not contain the required external task id.', msg);
14
14
  }
15
15
 
16
- eventEmitter.emit(`handle-${flowNodeInstanceId}`, msg, false);
16
+ eventEmitter.emit(`finish-${externalTaskId}`, msg.payload);
17
17
  });
18
18
  }
19
19
  RED.nodes.registerType('externaltask-output', ExternalTaskOutput);
@@ -6,10 +6,18 @@ module.exports = function (RED) {
6
6
  function MessageEventTrigger(config) {
7
7
  RED.nodes.createNode(this, config);
8
8
  var node = this;
9
+ var nodeContext = node.context();
9
10
 
10
11
  this.engine = this.server = RED.nodes.getNode(config.engine);
11
12
 
12
- const client = this.engine.getEngineClient();
13
+ const engineUrl = this.engine?.url || process.env.ENGINE_URL || 'http://engine:8000';
14
+
15
+ var client = nodeContext.get('client');
16
+
17
+ if (!client) {
18
+ nodeContext.set('client', new engine_client.EngineClient(engineUrl));
19
+ client = nodeContext.get('client');
20
+ }
13
21
 
14
22
  node.on('input', function (msg) {
15
23
  client.events
@@ -22,11 +30,7 @@ module.exports = function (RED) {
22
30
  msg.payload = result;
23
31
 
24
32
  node.send(msg);
25
- node.status({
26
- fill: 'blue',
27
- shape: 'dot',
28
- text: `message event triggered`,
29
- });
33
+ node.status({ fill: 'blue', shape: 'dot', text: `message event triggered` });
30
34
  })
31
35
  .catch((error) => {
32
36
  node.error(error);