@5minds/node-red-contrib-processcube 1.5.6-feature-aa14a2-m3pntyi8 → 1.5.7-develop-41d845-m3q6c4hg

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,13 +4,6 @@ module.exports = function (RED) {
4
4
  var node = this;
5
5
  node.engine = RED.nodes.getNode(config.engine);
6
6
 
7
- const eventEmitter = node.engine.eventEmitter;
8
-
9
- eventEmitter.on('engine-client-changed', () => {
10
- node.log('new engineClient received');
11
- register();
12
- });
13
-
14
7
  const register = async () => {
15
8
  const client = node.engine.engineClient;
16
9
 
@@ -18,7 +11,7 @@ module.exports = function (RED) {
18
11
  node.error('No engine configured.');
19
12
  return;
20
13
  }
21
-
14
+
22
15
  let currentIdentity = node.engine.identity;
23
16
 
24
17
  let subscription = null;
@@ -30,23 +23,24 @@ module.exports = function (RED) {
30
23
  payload: endEventFinished,
31
24
  });
32
25
  },
33
- { identity: currentIdentity }
26
+ { identity: currentIdentity },
34
27
  );
35
28
 
36
29
  node.engine.registerOnIdentityChanged(async (identity) => {
37
30
  client.events.removeSubscription(subscription, currentIdentity);
38
-
31
+
39
32
  currentIdentity = identity;
40
33
 
41
34
  subscription = await client.events.onEndEventFinished(
42
35
  (endEventFinished) => {
43
36
  node.send({
44
- payload: endEventFinished,
37
+ payload: endEventFinished
45
38
  });
46
39
  },
47
- { identity: currentIdentity }
40
+ { identity: currentIdentity },
48
41
  );
49
42
  });
43
+
50
44
  } catch (error) {
51
45
  node.error(error);
52
46
  }
@@ -4,13 +4,6 @@ module.exports = function (RED) {
4
4
  var node = this;
5
5
  node.engine = RED.nodes.getNode(config.engine);
6
6
 
7
- const eventEmitter = node.engine.eventEmitter;
8
-
9
- eventEmitter.on('engine-client-changed', () => {
10
- node.log('new engineClient received');
11
- register();
12
- });
13
-
14
7
  const register = async () => {
15
8
  let currentIdentity = node.engine.identity;
16
9
 
@@ -58,11 +58,26 @@
58
58
  Waiting for external tasks that correspond to the `Topic` configured in
59
59
  the connected ProcessCube Engine for processing.
60
60
 
61
+ ## Configs
62
+
63
+ : name (string) : The name of the node
64
+ : engine (string) : The ProcessCube Engine to connect to
65
+ : topic (string) : The topic of the external task
66
+ : workerConfig (object) : The configuration for the worker
67
+
68
+ ### workerConfig
69
+
70
+ - workerId (string): The id of the worker
71
+ - lockDuration (number): The duration in milliseconds the external task is locked for execution
72
+ - maxTasks (number): The maximum number of tasks that can be fetched at once
73
+ - longpollingTimeout (number): The duration in milliseconds the external task is locked for execution
74
+ - payloadFilter (Req-Expression): The filter for the payload of the external task
75
+
61
76
  ## Outputs
62
77
 
63
78
  : payload (string) : The payload the external task was started with.
64
79
  : task (object) : The external task object
65
- : flowNodeInstanceId : The unique identifier of the external task, which is needed to complete the task
80
+ : flowNodeInstanceId (string) : The unique identifier of the external task, which is needed to complete the task
66
81
 
67
82
  ### Details
68
83
 
@@ -32,149 +32,135 @@ module.exports = function (RED) {
32
32
  eventEmitter = flowContext.get('emitter');
33
33
  }
34
34
 
35
- const engineEventEmitter = node.engine.eventEmitter;
35
+ const etwCallback = async (payload, externalTask) => {
36
+ const saveHandleCallback = (data, callback) => {
37
+ try {
38
+ callback(data);
39
+ } catch (error) {
40
+ node.error(`Error in callback 'saveHandleCallback': ${error.message}`);
41
+ }
42
+ };
36
43
 
37
- engineEventEmitter.on('engine-client-changed', () => {
38
- node.log('new engineClient received');
39
- register();
40
- });
44
+ return await new Promise((resolve, reject) => {
45
+ const handleFinishTask = (msg) => {
46
+ let result = RED.util.encodeObject(msg.payload);
41
47
 
42
- const register = async () => {
43
- const etwCallback = async (payload, externalTask) => {
44
- const saveHandleCallback = (data, callback) => {
45
- try {
46
- callback(data);
47
- } catch (error) {
48
- node.error(`Error in callback 'saveHandleCallback': ${error.message}`);
48
+ node.log(
49
+ `handle event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* ${externalTask.processInstanceId} with result ${result} on msg._msgid ${msg._msgid}.`
50
+ );
51
+
52
+ if (externalTask.flowNodeInstanceId) {
53
+ delete started_external_tasks[externalTask.flowNodeInstanceId];
49
54
  }
50
- };
51
55
 
52
- return await new Promise((resolve, reject) => {
53
- const handleFinishTask = (msg) => {
54
- let result = RED.util.encodeObject(msg.payload);
56
+ showStatus(node, Object.keys(started_external_tasks).length);
55
57
 
56
- node.log(
57
- `handle event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* ${externalTask.processInstanceId} with result ${result} on msg._msgid ${msg._msgid}.`
58
- );
58
+ //resolve(result);
59
+ saveHandleCallback(result, resolve);
60
+ };
59
61
 
60
- if (externalTask.flowNodeInstanceId) {
61
- delete started_external_tasks[externalTask.flowNodeInstanceId];
62
- }
62
+ const handleErrorTask = (msg) => {
63
+ node.log(
64
+ `handle error event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' on *msg._msgid* '${msg._msgid}'.`
65
+ );
63
66
 
64
- showStatus(node, Object.keys(started_external_tasks).length);
67
+ if (externalTask.flowNodeInstanceId) {
68
+ delete started_external_tasks[externalTask.flowNodeInstanceId];
69
+ }
65
70
 
66
- //resolve(result);
67
- saveHandleCallback(result, resolve);
68
- };
71
+ showStatus(node, Object.keys(started_external_tasks).length);
69
72
 
70
- const handleErrorTask = (msg) => {
71
- node.log(
72
- `handle error event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' on *msg._msgid* '${msg._msgid}'.`
73
- );
73
+ // TODO: with reject, the default error handling is proceed
74
+ // SEE: https://github.com/5minds/ProcessCube.Engine.Client.ts/blob/develop/src/ExternalTaskWorker.ts#L180
75
+ // reject(result);
76
+ //resolve(msg);
77
+ saveHandleCallback(msg, resolve);
78
+ };
79
+
80
+ eventEmitter.once(`handle-${externalTask.flowNodeInstanceId}`, (msg, isError = false) => {
81
+ node.log(
82
+ `handle event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' with *msg._msgid* '${msg._msgid}' and *isError* '${isError}'`
83
+ );
74
84
 
75
- if (externalTask.flowNodeInstanceId) {
76
- delete started_external_tasks[externalTask.flowNodeInstanceId];
77
- }
85
+ if (isError) {
86
+ handleErrorTask(msg);
87
+ } else {
88
+ handleFinishTask(msg);
89
+ }
90
+ });
78
91
 
79
- showStatus(node, Object.keys(started_external_tasks).length);
92
+ started_external_tasks[externalTask.flowNodeInstanceId] = externalTask;
80
93
 
81
- // TODO: with reject, the default error handling is proceed
82
- // SEE: https://github.com/5minds/ProcessCube.Engine.Client.ts/blob/develop/src/ExternalTaskWorker.ts#L180
83
- // reject(result);
84
- //resolve(msg);
85
- saveHandleCallback(msg, resolve);
86
- };
94
+ showStatus(node, Object.keys(started_external_tasks).length);
87
95
 
88
- eventEmitter.once(`handle-${externalTask.flowNodeInstanceId}`, (msg, isError = false) => {
89
- node.log(
90
- `handle event for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' with *msg._msgid* '${msg._msgid}' and *isError* '${isError}'`
91
- );
96
+ let msg = {
97
+ _msgid: RED.util.generateId(),
98
+ task: RED.util.encodeObject(externalTask),
99
+ payload: payload,
100
+ flowNodeInstanceId: externalTask.flowNodeInstanceId,
101
+ processInstanceId: externalTask.processInstanceId,
102
+ };
92
103
 
93
- if (isError) {
94
- handleErrorTask(msg);
95
- } else {
96
- handleFinishTask(msg);
97
- }
98
- });
104
+ node.log(
105
+ `Received *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' with *msg._msgid* '${msg._msgid}'`
106
+ );
99
107
 
100
- started_external_tasks[externalTask.flowNodeInstanceId] = externalTask;
108
+ node.send(msg);
109
+ });
110
+ };
101
111
 
102
- showStatus(node, Object.keys(started_external_tasks).length);
112
+ let options = RED.util.evaluateNodeProperty(config.workerConfig, 'json', node);
103
113
 
104
- let msg = {
105
- _msgid: RED.util.generateId(),
106
- task: RED.util.encodeObject(externalTask),
107
- payload: payload,
108
- flowNodeInstanceId: externalTask.flowNodeInstanceId,
109
- processInstanceId: externalTask.processInstanceId,
110
- };
114
+ client.externalTasks
115
+ .subscribeToExternalTaskTopic(config.topic, etwCallback, options)
116
+ .then(async (externalTaskWorker) => {
117
+ node.status({ fill: 'blue', shape: 'ring', text: 'subcribed' });
111
118
 
112
- node.log(
113
- `Received *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}' with *msg._msgid* '${msg._msgid}'`
114
- );
119
+ externalTaskWorker.identity = engine.identity;
120
+ engine.registerOnIdentityChanged((identity) => {
121
+ externalTaskWorker.identity = identity;
122
+ });
115
123
 
116
- node.send(msg);
124
+ // export type WorkerErrorHandler = (errorType: 'fetchAndLock' | 'extendLock' | 'processExternalTask' | 'finishExternalTask', error: Error, externalTask?: ExternalTask<any>) => void;
125
+ externalTaskWorker.onWorkerError((errorType, error, externalTask) => {
126
+ switch (errorType) {
127
+ case 'extendLock':
128
+ case 'finishExternalTask':
129
+ case 'processExternalTask':
130
+ node.error(
131
+ `Worker error ${errorType} for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}': ${error.message}`
132
+ );
133
+
134
+ if (externalTask) {
135
+ delete started_external_tasks[externalTask.flowNodeInstanceId];
136
+ }
137
+
138
+ showStatus(node, Object.keys(started_external_tasks).length);
139
+ break;
140
+ default:
141
+ // reduce noise error logs
142
+ // node.error(`Worker error ${errorType}: ${error.message}`);
143
+ break;
144
+ }
117
145
  });
118
- };
119
146
 
120
- client.externalTasks
121
- .subscribeToExternalTaskTopic(
122
- config.topic,
123
- etwCallback,
124
- RED.util.evaluateNodeProperty(config.workerConfig, 'json', node)
125
- )
126
- .then(async (externalTaskWorker) => {
127
- node.status({ fill: 'blue', shape: 'ring', text: 'subcribed' });
128
-
129
- externalTaskWorker.identity = engine.identity;
130
- engine.registerOnIdentityChanged((identity) => {
131
- externalTaskWorker.identity = identity;
132
- });
133
-
134
- // export type WorkerErrorHandler = (errorType: 'fetchAndLock' | 'extendLock' | 'processExternalTask' | 'finishExternalTask', error: Error, externalTask?: ExternalTask<any>) => void;
135
- externalTaskWorker.onWorkerError((errorType, error, externalTask) => {
136
- switch (errorType) {
137
- case 'extendLock':
138
- case 'finishExternalTask':
139
- case 'processExternalTask':
140
- node.error(
141
- `Worker error ${errorType} for *external task flowNodeInstanceId* '${externalTask.flowNodeInstanceId}' and *processInstanceId* '${externalTask.processInstanceId}': ${error.message}`
142
- );
143
-
144
- if (externalTask) {
145
- delete started_external_tasks[externalTask.flowNodeInstanceId];
146
- }
147
-
148
- showStatus(node, Object.keys(started_external_tasks).length);
149
- break;
150
- default:
151
- node.error(`Worker error ${errorType}: ${error.message}`);
152
- break;
153
- }
154
- });
147
+ try {
148
+ externalTaskWorker.start();
149
+ } catch (error) {
150
+ node.error(`Worker start 'externalTaskWorker.start' failed: ${error.message}`);
151
+ }
155
152
 
153
+ node.on('close', () => {
156
154
  try {
157
- externalTaskWorker.start();
158
- } catch (error) {
159
- node.error(`Worker start 'externalTaskWorker.start' failed: ${error.message}`);
155
+ externalTaskWorker.stop();
156
+ } catch {
157
+ node.error('Client close failed');
160
158
  }
161
-
162
- node.on('close', () => {
163
- try {
164
- externalTaskWorker.stop();
165
- } catch {
166
- node.error('Client close failed');
167
- }
168
- });
169
- })
170
- .catch((error) => {
171
- node.error(`Error in subscribeToExternalTaskTopic: ${error.message}`);
172
159
  });
173
- };
174
-
175
- if (node.engine) {
176
- register();
177
- }
160
+ })
161
+ .catch((error) => {
162
+ node.error(`Error in subscribeToExternalTaskTopic: ${error.message}`);
163
+ });
178
164
  }
179
165
 
180
166
  RED.nodes.registerType('externaltask-input', ExternalTaskInput);
@@ -71,6 +71,22 @@
71
71
  "info": "",
72
72
  "env": []
73
73
  },
74
+ {
75
+ "id": "76c047e0d8770a20",
76
+ "type": "tab",
77
+ "label": "Other Events",
78
+ "disabled": false,
79
+ "info": "",
80
+ "env": []
81
+ },
82
+ {
83
+ "id": "2766c40d84283368",
84
+ "type": "tab",
85
+ "label": "Placeholder",
86
+ "disabled": false,
87
+ "info": "",
88
+ "env": []
89
+ },
74
90
  {
75
91
  "id": "4c59118134081e05",
76
92
  "type": "group",
@@ -481,6 +497,7 @@
481
497
  "color": "#a4a4a4"
482
498
  },
483
499
  "nodes": [
500
+
484
501
  "2fadb4c4667ecaf2",
485
502
  "93331783b7ef3fc5",
486
503
  "bc26f9821540f097",
@@ -1485,7 +1502,7 @@
1485
1502
  "g": "a71a168415778e2c",
1486
1503
  "name": "",
1487
1504
  "engine": "42e6796dddd9d4db",
1488
- "query": "{\"includeXml\":false}",
1505
+ "query": "{\"includeXml\":false,\"processDefinitionId\":\"External-Task-Sample_Definition\"}",
1489
1506
  "query_type": "json",
1490
1507
  "x": 320,
1491
1508
  "y": 140,
@@ -2094,5 +2111,95 @@
2094
2111
  "x": 760,
2095
2112
  "y": 60,
2096
2113
  "wires": []
2114
+ },
2115
+ {
2116
+ "id": "930624edc6169c55",
2117
+ "type": "process-event-listener",
2118
+ "z": "76c047e0d8770a20",
2119
+ "g": "865723b71ced9418",
2120
+ "name": "",
2121
+ "engine": "42e6796dddd9d4db",
2122
+ "processmodel": "External-Task-Sample_Process",
2123
+ "eventtype": "starting",
2124
+ "query": "{}",
2125
+ "query_type": "json",
2126
+ "x": 160,
2127
+ "y": 140,
2128
+ "wires": [
2129
+ [
2130
+ "2f2ec1cc0213eab5"
2131
+ ]
2132
+ ]
2133
+ },
2134
+ {
2135
+ "id": "2f2ec1cc0213eab5",
2136
+ "type": "debug",
2137
+ "z": "76c047e0d8770a20",
2138
+ "g": "865723b71ced9418",
2139
+ "name": "debug 34",
2140
+ "active": true,
2141
+ "tosidebar": true,
2142
+ "console": false,
2143
+ "tostatus": false,
2144
+ "complete": "false",
2145
+ "statusVal": "",
2146
+ "statusType": "auto",
2147
+ "x": 430,
2148
+ "y": 140,
2149
+ "wires": []
2150
+ },
2151
+ {
2152
+ "id": "bde205e77cd20558",
2153
+ "type": "comment",
2154
+ "z": "76c047e0d8770a20",
2155
+ "g": "865723b71ced9418",
2156
+ "name": "Hört auf die Events der Processe",
2157
+ "info": "",
2158
+ "x": 190,
2159
+ "y": 80,
2160
+ "wires": []
2161
+ },
2162
+ {
2163
+ "id": "03ac7bc273197c45",
2164
+ "type": "process-terminate",
2165
+ "z": "2766c40d84283368",
2166
+ "g": "9081b057a931f0cf",
2167
+ "name": "",
2168
+ "engine": "42e6796dddd9d4db",
2169
+ "x": 170,
2170
+ "y": 140,
2171
+ "wires": [
2172
+ [
2173
+ "bb734a85d4b37728"
2174
+ ]
2175
+ ]
2176
+ },
2177
+ {
2178
+ "id": "bb734a85d4b37728",
2179
+ "type": "debug",
2180
+ "z": "2766c40d84283368",
2181
+ "g": "9081b057a931f0cf",
2182
+ "name": "debug 35",
2183
+ "active": true,
2184
+ "tosidebar": true,
2185
+ "console": false,
2186
+ "tostatus": false,
2187
+ "complete": "false",
2188
+ "statusVal": "",
2189
+ "statusType": "auto",
2190
+ "x": 370,
2191
+ "y": 140,
2192
+ "wires": []
2193
+ },
2194
+ {
2195
+ "id": "3d03550f7d93bfd3",
2196
+ "type": "comment",
2197
+ "z": "2766c40d84283368",
2198
+ "g": "9081b057a931f0cf",
2199
+ "name": "Event for Terminating a Process",
2200
+ "info": "",
2201
+ "x": 210,
2202
+ "y": 80,
2203
+ "wires": []
2097
2204
  }
2098
2205
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@5minds/node-red-contrib-processcube",
3
- "version": "1.5.6-feature-aa14a2-m3pntyi8",
3
+ "version": "1.5.7-develop-41d845-m3q6c4hg",
4
4
  "license": "MIT",
5
5
  "description": "Node-RED nodes for ProcessCube",
6
6
  "scripts": {
@@ -4,13 +4,6 @@ module.exports = function (RED) {
4
4
  var node = this;
5
5
  node.engine = RED.nodes.getNode(config.engine);
6
6
 
7
- const eventEmitter = node.engine.eventEmitter;
8
-
9
- eventEmitter.on('engine-client-changed', () => {
10
- node.log('new engineClient received');
11
- register();
12
- });
13
-
14
7
  const register = async () => {
15
8
  const client = node.engine.engineClient;
16
9
 
@@ -31,8 +24,7 @@ module.exports = function (RED) {
31
24
  async (processNotification) => {
32
25
  if (
33
26
  config.processmodel != '' &&
34
- config.processmodel != processNotification.processModelId
35
- ) {
27
+ config.processmodel != processNotification.processModelId) {
36
28
  return;
37
29
  }
38
30
 
@@ -73,8 +65,7 @@ module.exports = function (RED) {
73
65
  async (processNotification) => {
74
66
  if (
75
67
  config.processmodel != '' &&
76
- config.processmodel != processNotification.processModelId
77
- ) {
68
+ config.processmodel != processNotification.processModelId) {
78
69
  return;
79
70
  }
80
71
 
@@ -442,6 +433,7 @@ module.exports = function (RED) {
442
433
  },
443
434
  { identity: currentIdentity }
444
435
  );
436
+
445
437
  });
446
438
 
447
439
  node.on('close', () => {
@@ -29,9 +29,10 @@
29
29
  <script type="text/markdown" data-help-name="process-terminate">
30
30
  Terminate an instance of a process model in the ProcessCube.
31
31
 
32
- ## Inputs
32
+ ## Configs
33
33
 
34
- : payload (string): The id of the processinstance that is going to be terminated.
34
+ : name (string): name of the node
35
+ : engine (string): the engine to connect to
35
36
 
36
37
  ## Outputs
37
38
 
@@ -1,4 +1,3 @@
1
- const EventEmitter = require('node:events');
2
1
  const engine_client = require('@5minds/processcube_engine_client');
3
2
  const jwt = require('jwt-decode');
4
3
  const oidc = require('openid-client');
@@ -13,8 +12,7 @@ module.exports = function (RED) {
13
12
  this.credentials.clientId = RED.util.evaluateNodeProperty(n.clientId, n.clientIdType, node);
14
13
  this.credentials.clientSecret = RED.util.evaluateNodeProperty(n.clientSecret, n.clientSecretType, node);
15
14
 
16
- node.eventEmitter = new EventEmitter();
17
-
15
+ // known issue: kann bei falschem timing zu laufzeitfehlern führen (absprache MM)
18
16
  // set the engine url
19
17
  const stopRefreshing = periodicallyRefreshEngineClient(this, n, 10000);
20
18
 
@@ -43,7 +41,7 @@ module.exports = function (RED) {
43
41
  function refreshUrl() {
44
42
  const newUrl = RED.util.evaluateNodeProperty(n.url, n.urlType, node);
45
43
 
46
- if (node.url === newUrl) {
44
+ if (node.url == newUrl) {
47
45
  return;
48
46
  }
49
47
 
@@ -55,15 +53,11 @@ module.exports = function (RED) {
55
53
  node.engineClient = new engine_client.EngineClient(node.url, () =>
56
54
  getFreshIdentity(node.url, node)
57
55
  );
58
-
59
- node.eventEmitter.emit('engine-client-changed');
60
56
  } else {
61
57
  if (this.engineClient) {
62
58
  this.engineClient.dispose();
63
59
  }
64
60
  node.engineClient = new engine_client.EngineClient(node.url);
65
-
66
- node.eventEmitter.emit('engine-client-changed');
67
61
  }
68
62
  }
69
63