bpmn-elements 6.0.1 → 7.0.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.
Files changed (116) hide show
  1. package/CHANGELOG.md +322 -0
  2. package/README.md +3 -0
  3. package/dist/index.js +52 -44
  4. package/dist/src/Api.js +77 -76
  5. package/dist/src/Context.js +169 -175
  6. package/dist/src/Environment.js +90 -102
  7. package/dist/src/EventBroker.js +89 -88
  8. package/dist/src/ExtensionsMapper.js +2 -2
  9. package/dist/src/MessageFormatter.js +164 -95
  10. package/dist/src/Scripts.js +6 -2
  11. package/dist/src/activity/Activity.js +1106 -916
  12. package/dist/src/activity/ActivityExecution.js +342 -297
  13. package/dist/src/activity/Dummy.js +3 -3
  14. package/dist/src/definition/Definition.js +498 -444
  15. package/dist/src/definition/DefinitionExecution.js +722 -409
  16. package/dist/src/error/Errors.js +17 -7
  17. package/dist/src/eventDefinitions/CancelEventDefinition.js +190 -150
  18. package/dist/src/eventDefinitions/CompensateEventDefinition.js +194 -161
  19. package/dist/src/eventDefinitions/ConditionalEventDefinition.js +197 -135
  20. package/dist/src/eventDefinitions/ErrorEventDefinition.js +207 -165
  21. package/dist/src/eventDefinitions/EscalationEventDefinition.js +175 -141
  22. package/dist/src/eventDefinitions/EventDefinitionExecution.js +157 -129
  23. package/dist/src/eventDefinitions/LinkEventDefinition.js +174 -149
  24. package/dist/src/eventDefinitions/MessageEventDefinition.js +213 -176
  25. package/dist/src/eventDefinitions/SignalEventDefinition.js +203 -161
  26. package/dist/src/eventDefinitions/TerminateEventDefinition.js +21 -23
  27. package/dist/src/eventDefinitions/TimerEventDefinition.js +243 -228
  28. package/dist/src/events/BoundaryEvent.js +180 -144
  29. package/dist/src/events/EndEvent.js +18 -23
  30. package/dist/src/events/IntermediateCatchEvent.js +44 -58
  31. package/dist/src/events/IntermediateThrowEvent.js +18 -23
  32. package/dist/src/events/StartEvent.js +109 -94
  33. package/dist/src/flows/Association.js +94 -100
  34. package/dist/src/flows/MessageFlow.js +86 -103
  35. package/dist/src/flows/SequenceFlow.js +173 -182
  36. package/dist/src/gateways/EventBasedGateway.js +88 -84
  37. package/dist/src/gateways/ExclusiveGateway.js +13 -16
  38. package/dist/src/gateways/InclusiveGateway.js +11 -14
  39. package/dist/src/gateways/ParallelGateway.js +11 -14
  40. package/dist/src/getPropertyValue.js +34 -34
  41. package/dist/src/io/BpmnIO.js +17 -14
  42. package/dist/src/io/EnvironmentDataObject.js +33 -29
  43. package/dist/src/io/EnvironmentDataStore.js +33 -29
  44. package/dist/src/io/EnvironmentDataStoreReference.js +35 -31
  45. package/dist/src/io/InputOutputSpecification.js +177 -168
  46. package/dist/src/io/Properties.js +117 -124
  47. package/dist/src/messageHelper.js +1 -1
  48. package/dist/src/process/Process.js +433 -359
  49. package/dist/src/process/ProcessExecution.js +744 -645
  50. package/dist/src/shared.js +2 -2
  51. package/dist/src/tasks/CallActivity.js +160 -0
  52. package/dist/src/tasks/LoopCharacteristics.js +309 -330
  53. package/dist/src/tasks/ReceiveTask.js +233 -182
  54. package/dist/src/tasks/ScriptTask.js +35 -41
  55. package/dist/src/tasks/ServiceImplementation.js +13 -20
  56. package/dist/src/tasks/ServiceTask.js +82 -75
  57. package/dist/src/tasks/SignalTask.js +97 -93
  58. package/dist/src/tasks/StandardLoopCharacteristics.js +1 -1
  59. package/dist/src/tasks/SubProcess.js +195 -175
  60. package/dist/src/tasks/Task.js +17 -19
  61. package/index.js +2 -0
  62. package/package.json +13 -13
  63. package/src/Api.js +65 -59
  64. package/src/Context.js +138 -141
  65. package/src/Environment.js +88 -100
  66. package/src/EventBroker.js +67 -68
  67. package/src/ExtensionsMapper.js +2 -2
  68. package/src/MessageFormatter.js +132 -74
  69. package/src/activity/Activity.js +915 -775
  70. package/src/activity/ActivityExecution.js +293 -247
  71. package/src/activity/Dummy.js +2 -2
  72. package/src/definition/Definition.js +436 -401
  73. package/src/definition/DefinitionExecution.js +603 -343
  74. package/src/error/Errors.js +11 -6
  75. package/src/eventDefinitions/CancelEventDefinition.js +164 -121
  76. package/src/eventDefinitions/CompensateEventDefinition.js +158 -124
  77. package/src/eventDefinitions/ConditionalEventDefinition.js +147 -104
  78. package/src/eventDefinitions/ErrorEventDefinition.js +190 -131
  79. package/src/eventDefinitions/EscalationEventDefinition.js +139 -101
  80. package/src/eventDefinitions/EventDefinitionExecution.js +127 -95
  81. package/src/eventDefinitions/LinkEventDefinition.js +160 -129
  82. package/src/eventDefinitions/MessageEventDefinition.js +178 -121
  83. package/src/eventDefinitions/SignalEventDefinition.js +162 -106
  84. package/src/eventDefinitions/TerminateEventDefinition.js +19 -19
  85. package/src/eventDefinitions/TimerEventDefinition.js +202 -167
  86. package/src/events/BoundaryEvent.js +156 -115
  87. package/src/events/EndEvent.js +15 -18
  88. package/src/events/IntermediateCatchEvent.js +40 -44
  89. package/src/events/IntermediateThrowEvent.js +15 -18
  90. package/src/events/StartEvent.js +84 -50
  91. package/src/flows/Association.js +98 -112
  92. package/src/flows/MessageFlow.js +81 -97
  93. package/src/flows/SequenceFlow.js +146 -160
  94. package/src/gateways/EventBasedGateway.js +75 -68
  95. package/src/gateways/ExclusiveGateway.js +8 -13
  96. package/src/gateways/InclusiveGateway.js +8 -13
  97. package/src/gateways/ParallelGateway.js +8 -13
  98. package/src/getPropertyValue.js +34 -33
  99. package/src/io/BpmnIO.js +16 -15
  100. package/src/io/EnvironmentDataObject.js +29 -18
  101. package/src/io/EnvironmentDataStore.js +29 -18
  102. package/src/io/EnvironmentDataStoreReference.js +31 -20
  103. package/src/io/InputOutputSpecification.js +154 -157
  104. package/src/io/Properties.js +95 -97
  105. package/src/process/Process.js +374 -333
  106. package/src/process/ProcessExecution.js +606 -554
  107. package/src/tasks/CallActivity.js +130 -0
  108. package/src/tasks/LoopCharacteristics.js +290 -289
  109. package/src/tasks/ReceiveTask.js +174 -107
  110. package/src/tasks/ScriptTask.js +27 -30
  111. package/src/tasks/ServiceImplementation.js +13 -18
  112. package/src/tasks/ServiceTask.js +67 -60
  113. package/src/tasks/SignalTask.js +77 -52
  114. package/src/tasks/StandardLoopCharacteristics.js +1 -1
  115. package/src/tasks/SubProcess.js +184 -157
  116. package/src/tasks/Task.js +15 -19
@@ -2,696 +2,748 @@ import {ProcessApi} from '../Api';
2
2
  import {cloneContent, cloneMessage, pushParent} from '../messageHelper';
3
3
  import {getUniqueId} from '../shared';
4
4
 
5
- export default function ProcessExecution(parentActivity, context) {
6
- const {id, type, broker, logger, isSubProcess} = parentActivity;
7
- const {environment} = context;
8
-
9
- const children = context.getActivities(id);
10
- const flows = context.getSequenceFlows(id);
11
- const associations = context.getAssociations(id);
12
- const outboundMessageFlows = context.getMessageFlows(id);
13
-
14
- const startActivities = [];
15
- const triggeredByEventActivities = [];
16
- const detachedActivities = [];
17
-
18
- const postponed = [];
19
- const startSequences = {};
20
- const exchangeName = isSubProcess ? 'subprocess-execution' : 'execution';
21
- broker.assertExchange(exchangeName, 'topic', {autoDelete: false, durable: true});
22
-
23
- let activityQ, status = 'init', executionId, stopped, activated, stateMessage, completed = false, executionName;
24
-
25
- const processExecution = {
26
- id,
27
- type,
28
- broker,
29
- get environment() {
30
- return environment;
31
- },
32
- get executionId() {
33
- return executionId;
34
- },
35
- get completed() {
36
- return completed;
37
- },
38
- get status() {
39
- return status;
40
- },
41
- get stopped() {
42
- return stopped;
43
- },
44
- get postponedCount() {
45
- return postponed.length;
46
- },
47
- get isRunning() {
48
- if (activated) return true;
49
- return false;
50
- },
51
- discard,
52
- execute,
53
- getApi,
54
- getActivityById,
55
- getActivities,
56
- getPostponed,
57
- getSequenceFlows,
58
- getState,
59
- recover,
60
- shake,
61
- stop,
5
+ export default ProcessExecution;
6
+
7
+ const activatedSymbol = Symbol.for('activated');
8
+ const activityQSymbol = Symbol.for('activityQ');
9
+ const completedSymbol = Symbol.for('completed');
10
+ const elementsSymbol = Symbol.for('elements');
11
+ const executeMessageSymbol = Symbol.for('executeMessage');
12
+ const messageHandlersSymbol = Symbol.for('messageHandlers');
13
+ const parentSymbol = Symbol.for('parent');
14
+ const statusSymbol = Symbol.for('status');
15
+ const stoppedSymbol = Symbol.for('stopped');
16
+
17
+ function ProcessExecution(parentActivity, context) {
18
+ const {id, type, broker, isSubProcess} = parentActivity;
19
+
20
+ this[parentSymbol] = parentActivity;
21
+ this.id = id;
22
+ this.type = type;
23
+ this.isSubProcess = isSubProcess;
24
+ this.broker = broker;
25
+ this.environment = context.environment;
26
+ this.context = context;
27
+
28
+ this[elementsSymbol] = {
29
+ children: context.getActivities(id),
30
+ associations: context.getAssociations(id),
31
+ flows: context.getSequenceFlows(id),
32
+ outboundMessageFlows: context.getMessageFlows(id),
33
+ startActivities: [],
34
+ triggeredByEvent: [],
35
+ detachedActivities: [],
36
+ startSequences: {},
37
+ postponed: [],
62
38
  };
63
39
 
64
- return processExecution;
65
-
66
- function execute(executeMessage) {
67
- if (!executeMessage) throw new Error('Process execution requires message');
68
- if (!executeMessage.content || !executeMessage.content.executionId) throw new Error('Process execution requires execution id');
69
-
70
- const isRedelivered = executeMessage.fields.redelivered;
71
- executionId = executeMessage.content.executionId;
72
- prepare();
73
-
74
- stateMessage = cloneMessage(executeMessage);
75
- stateMessage.content = {...stateMessage.content, executionId, state: 'start'};
76
-
77
- stopped = false;
78
-
79
- environment.assignVariables(executeMessage);
80
- activityQ = broker.assertQueue(`execute-${executionId}-q`, {durable: true, autoDelete: false});
40
+ const exchangeName = this._exchangeName = isSubProcess ? 'subprocess-execution' : 'execution';
41
+ broker.assertExchange(exchangeName, 'topic', {autoDelete: false, durable: true});
81
42
 
82
- if (isRedelivered) {
83
- return resume();
84
- }
43
+ this[completedSymbol] = false;
44
+ this[stoppedSymbol] = false;
45
+ this[activatedSymbol] = false;
46
+ this[statusSymbol] = 'init';
47
+ this.executionId = undefined;
48
+
49
+ this[messageHandlersSymbol] = {
50
+ onActivityEvent: this._onActivityEvent.bind(this),
51
+ onApiMessage: this._onApiMessage.bind(this),
52
+ onChildMessage: this._onChildMessage.bind(this),
53
+ onMessageFlowEvent: this._onMessageFlowEvent.bind(this),
54
+ };
55
+ }
85
56
 
86
- logger.debug(`<${executionName}> execute`, isSubProcess ? 'sub process' : 'process');
87
- activate();
88
- start();
89
- return true;
57
+ const proto = ProcessExecution.prototype;
58
+
59
+ Object.defineProperty(proto, 'stopped', {
60
+ enumerable: true,
61
+ get() {
62
+ return this[stoppedSymbol];
63
+ },
64
+ });
65
+
66
+ Object.defineProperty(proto, 'completed', {
67
+ enumerable: true,
68
+ get() {
69
+ return this[completedSymbol];
70
+ },
71
+ });
72
+
73
+ Object.defineProperty(proto, 'status', {
74
+ enumerable: true,
75
+ get() {
76
+ return this[statusSymbol];
77
+ },
78
+ });
79
+
80
+ Object.defineProperty(proto, 'postponedCount', {
81
+ get() {
82
+ return this[elementsSymbol].postponed.length;
83
+ },
84
+ });
85
+
86
+ Object.defineProperty(proto, 'isRunning', {
87
+ get() {
88
+ return this[activatedSymbol];
89
+ },
90
+ });
91
+
92
+ proto.execute = function execute(executeMessage) {
93
+ if (!executeMessage) throw new Error('Process execution requires message');
94
+ if (!executeMessage.content || !executeMessage.content.executionId) throw new Error('Process execution requires execution id');
95
+
96
+ const executionId = this.executionId = executeMessage.content.executionId;
97
+
98
+ this[executeMessageSymbol] = cloneMessage(executeMessage, {
99
+ executionId,
100
+ state: 'start',
101
+ });
102
+
103
+ this[stoppedSymbol] = false;
104
+
105
+ this.environment.assignVariables(executeMessage);
106
+ this[activityQSymbol] = this.broker.assertQueue(`execute-${executionId}-q`, {durable: true, autoDelete: false});
107
+
108
+ if (executeMessage.fields.redelivered) {
109
+ return this.resume();
90
110
  }
91
111
 
92
- function resume() {
93
- logger.debug(`<${executionName}> resume process execution at`, status);
112
+ this._debug(`execute ${this.isSubProcess ? 'sub process' : 'process'}`);
113
+ this._activate();
114
+ this._start();
115
+ return true;
116
+ };
94
117
 
95
- if (completed) return complete('completed');
118
+ proto.resume = function resume() {
119
+ this._debug(`resume process execution at ${this.status}`);
96
120
 
97
- activate();
98
-
99
- if (startActivities.length > 1) {
100
- startActivities.forEach((a) => a.shake());
101
- }
121
+ if (this[completedSymbol]) return this._complete('completed');
102
122
 
103
- postponed.splice(0);
104
- detachedActivities.splice(0);
105
- activityQ.consume(onChildMessage, {prefetch: 1000, consumerTag: `_process-activity-${executionId}`});
123
+ this._activate();
106
124
 
107
- if (completed) return complete('completed');
108
- switch (status) {
109
- case 'init':
110
- return start();
111
- case 'executing': {
112
- if (!postponed.length) return complete('completed');
113
- break;
114
- }
115
- }
125
+ const {startActivities, detachedActivities, postponed} = this[elementsSymbol];
116
126
 
117
- postponed.slice().forEach(({content}) => {
118
- const activity = getActivityById(content.id);
119
- if (!activity) return;
120
- if (content.placeholder) return;
121
- activity.resume();
122
- });
127
+ if (startActivities.length > 1) {
128
+ for (const a of startActivities) a.shake();
123
129
  }
124
130
 
125
- function start() {
126
- if (children.length === 0) {
127
- return complete('completed');
128
- }
129
-
130
- status = 'start';
131
+ postponed.splice(0);
132
+ detachedActivities.splice(0);
131
133
 
132
- const executeContent = {...stateMessage.content, state: status};
134
+ this[activityQSymbol].consume(this[messageHandlersSymbol].onChildMessage, {
135
+ prefetch: 1000,
136
+ consumerTag: `_process-activity-${this.executionId}`,
137
+ });
133
138
 
134
- broker.publish(exchangeName, 'execute.start', cloneContent(executeContent));
139
+ if (this[completedSymbol]) return this._complete('completed');
135
140
 
136
- if (startActivities.length > 1) {
137
- startActivities.forEach((a) => a.shake());
141
+ switch (this.status) {
142
+ case 'init':
143
+ return this._start();
144
+ case 'executing': {
145
+ if (!postponed.length) return this._complete('completed');
146
+ break;
138
147
  }
148
+ }
139
149
 
140
- startActivities.forEach((activity) => activity.init());
141
- startActivities.forEach((activity) => activity.run());
142
-
143
- postponed.splice(0);
144
- detachedActivities.splice(0);
145
- activityQ.assertConsumer(onChildMessage, {prefetch: 1000, consumerTag: `_process-activity-${executionId}`});
150
+ for (const {content} of postponed.slice()) {
151
+ const activity = this.getActivityById(content.id);
152
+ if (!activity) continue;
153
+ if (content.placeholder) continue;
154
+ activity.resume();
146
155
  }
156
+ };
147
157
 
148
- function recover(state) {
149
- if (!state) return processExecution;
150
- executionId = state.executionId;
151
- prepare();
158
+ proto.recover = function recover(state) {
159
+ if (!state) return this;
160
+ this.executionId = state.executionId;
152
161
 
153
- stopped = state.stopped;
154
- completed = state.completed;
155
- status = state.status;
162
+ this[stoppedSymbol] = state.stopped;
163
+ this[completedSymbol] = state.completed;
164
+ this[statusSymbol] = state.status;
156
165
 
157
- logger.debug(`<${executionName}> recover process execution at`, status);
166
+ this._debug(`recover process execution at ${this.status}`);
158
167
 
159
- if (state.messageFlows) {
160
- state.messageFlows.forEach((flowState) => {
161
- const flow = getMessageFlowById(flowState.id);
162
- if (!flow) return;
163
- flow.recover(flowState);
164
- });
168
+ if (state.messageFlows) {
169
+ for (const flowState of state.messageFlows) {
170
+ const flow = this._getMessageFlowById(flowState.id);
171
+ if (!flow) continue;
172
+ flow.recover(flowState);
165
173
  }
174
+ }
166
175
 
167
- if (state.associations) {
168
- state.associations.forEach((associationState) => {
169
- const association = getAssociationById(associationState.id);
170
- if (!association) return;
171
- association.recover(associationState);
172
- });
176
+ if (state.associations) {
177
+ for (const associationState of state.associations) {
178
+ const association = this._getAssociationById(associationState.id);
179
+ if (!association) continue;
180
+ association.recover(associationState);
173
181
  }
182
+ }
174
183
 
175
- if (state.flows) {
176
- state.flows.forEach((flowState) => {
177
- const flow = getFlowById(flowState.id);
178
- if (!flow) return;
179
- flow.recover(flowState);
180
- });
184
+ if (state.flows) {
185
+ for (const flowState of state.flows) {
186
+ const flow = this._getFlowById(flowState.id);
187
+ if (!flow) continue;
188
+ flow.recover(flowState);
181
189
  }
190
+ }
182
191
 
183
- if (state.children) {
184
- state.children.forEach((childState) => {
185
- const child = getActivityById(childState.id);
186
- if (!child) return;
192
+ if (state.children) {
193
+ for (const childState of state.children) {
194
+ const child = this.getActivityById(childState.id);
195
+ if (!child) continue;
187
196
 
188
- child.recover(childState);
189
- });
197
+ child.recover(childState);
190
198
  }
199
+ }
200
+
201
+ return this;
202
+ };
191
203
 
192
- return processExecution;
204
+ proto.shake = function shake(fromId) {
205
+ let executing = true;
206
+ const id = this.id;
207
+ if (!this.isRunning) {
208
+ executing = false;
209
+ this.executionId = getUniqueId(id);
210
+ this._activate();
193
211
  }
212
+ const toShake = fromId ? [this.getActivityById(fromId)].filter(Boolean) : this[elementsSymbol].startActivities;
194
213
 
195
- function shake(fromId) {
196
- let executing = true;
197
- if (!processExecution.isRunning) {
198
- executing = false;
199
- executionId = getUniqueId(id);
200
- prepare();
201
- activate();
202
- }
203
- const toShake = fromId ? [getActivityById(fromId)].filter(Boolean) : startActivities;
204
-
205
- const result = {};
206
- broker.subscribeTmp('event', '*.shake.*', (routingKey, {content}) => {
207
- let isLooped = false;
208
- switch (routingKey) {
209
- case 'flow.shake.loop':
210
- isLooped = true;
211
- case 'activity.shake.end':
212
- onShakeEnd(content, isLooped);
213
- break;
214
+ const result = {};
215
+ this.broker.subscribeTmp('event', '*.shake.*', (routingKey, {content}) => {
216
+ let isLooped = false;
217
+ switch (routingKey) {
218
+ case 'flow.shake.loop':
219
+ isLooped = true;
220
+ case 'activity.shake.end': {
221
+ const {id: shakeId, parent: shakeParent} = content;
222
+ if (shakeParent.id !== id) return;
223
+
224
+ result[shakeId] = result[shakeId] || [];
225
+ result[shakeId].push({...content, isLooped});
226
+ break;
214
227
  }
215
- }, {noAck: true, consumerTag: `_shaker-${executionId}`});
228
+ }
229
+ }, {noAck: true, consumerTag: `_shaker-${this.executionId}`});
216
230
 
217
- toShake.forEach((a) => a.shake());
231
+ for (const a of toShake) a.shake();
218
232
 
219
- if (!executing) deactivate();
220
- broker.cancel(`_shaker-${executionId}`);
233
+ if (!executing) this._deactivate();
234
+ this.broker.cancel(`_shaker-${this.executionId}`);
221
235
 
222
- return result;
236
+ return result;
237
+ };
223
238
 
224
- function onShakeEnd(content, isLooped) {
225
- const {id: shakeId, parent: shakeParent} = content;
226
- if (shakeParent.id !== id) return;
239
+ proto.stop = function stop() {
240
+ this.getApi().stop();
241
+ };
227
242
 
228
- result[shakeId] = result[shakeId] || [];
229
- result[shakeId].push({...content, isLooped});
243
+ proto.getPostponed = function getPostponed(filterFn) {
244
+ return this[elementsSymbol].postponed.slice().reduce((result, msg) => {
245
+ const api = this._getChildApi(msg);
246
+ if (api) {
247
+ if (filterFn && !filterFn(api)) return result;
248
+ result.push(api);
230
249
  }
231
- }
250
+ return result;
251
+ }, []);
252
+ };
253
+
254
+ proto.discard = function discard() {
255
+ this[statusSymbol] = 'discard';
256
+ return this[activityQSymbol].queueMessage({routingKey: 'execution.discard'}, {
257
+ id: this.id,
258
+ type: this.type,
259
+ executionId: this.executionId,
260
+ }, {type: 'discard'});
261
+ };
262
+
263
+
264
+ proto.getState = function getState() {
265
+ const {flows, outboundMessageFlows, associations} = this[elementsSymbol];
266
+ return {
267
+ executionId: this.executionId,
268
+ stopped: this[stoppedSymbol],
269
+ completed: this[completedSymbol],
270
+ status: this.status,
271
+ children: this[elementsSymbol].children.reduce((result, activity) => {
272
+ if (activity.placeholder) return result;
273
+ result.push(activity.getState());
274
+ return result;
275
+ }, []),
276
+ flows: flows.map((f) => f.getState()),
277
+ messageFlows: outboundMessageFlows.map((f) => f.getState()),
278
+ associations: associations.map((f) => f.getState()),
279
+ };
280
+ };
232
281
 
233
- function stop() {
234
- getApi().stop();
235
- }
282
+ proto.getActivities = function getActivities() {
283
+ return this[elementsSymbol].children.slice();
284
+ };
236
285
 
237
- function activate() {
238
- broker.subscribeTmp('api', '#', onApiMessage, {noAck: true, consumerTag: `_process-api-consumer-${executionId}`, priority: 200});
286
+ proto.getActivityById = function getActivityById(activityId) {
287
+ return this[elementsSymbol].children.find((child) => child.id === activityId);
288
+ };
239
289
 
240
- outboundMessageFlows.forEach((flow) => {
241
- flow.activate();
242
- flow.broker.subscribeTmp('event', '#', onMessageFlowEvent, {consumerTag: '_process-message-consumer', noAck: true, priority: 200});
243
- });
290
+ proto.getSequenceFlows = function getSequenceFlows() {
291
+ return this[elementsSymbol].flows.slice();
292
+ };
244
293
 
245
- flows.forEach((flow) => {
246
- flow.broker.subscribeTmp('event', '#', onActivityEvent, {consumerTag: '_process-flow-controller', noAck: true, priority: 200});
247
- });
294
+ proto.getApi = function getApi(message) {
295
+ if (!message) return ProcessApi(this.broker, this[executeMessageSymbol]);
248
296
 
249
- associations.forEach((association) => {
250
- association.broker.subscribeTmp('event', '#', onActivityEvent, {consumerTag: '_process-association-controller', noAck: true, priority: 200});
251
- });
297
+ const content = message.content;
252
298
 
253
- startActivities.splice(0);
254
- triggeredByEventActivities.splice(0);
255
-
256
- children.forEach((activity) => {
257
- if (activity.placeholder) return;
258
- activity.activate(processExecution);
259
- activity.broker.subscribeTmp('event', '#', onActivityEvent, {noAck: true, consumerTag: '_process-activity-consumer', priority: 200});
260
- if (activity.isStart) startActivities.push(activity);
261
- if (activity.triggeredByEvent) triggeredByEventActivities.push(activity);
262
- });
299
+ if (content.executionId !== this.executionId) {
300
+ return this._getChildApi(message);
301
+ }
263
302
 
264
- activated = true;
303
+ const api = ProcessApi(this.broker, message);
304
+ const postponed = this[elementsSymbol].postponed;
305
+ const self = this;
265
306
 
266
- function onActivityEvent(routingKey, activityMessage) {
267
- const message = cloneMessage(activityMessage);
268
- if (message.fields.redelivered && message.properties.persistent === false) return;
307
+ api.getExecuting = function getExecuting() {
308
+ return postponed.reduce((result, msg) => {
309
+ const childApi = self._getChildApi(msg);
310
+ if (childApi) result.push(childApi);
311
+ return result;
312
+ }, []);
313
+ };
269
314
 
270
- const content = message.content;
271
- const parent = content.parent = content.parent || {};
272
- let delegate = message.properties.delegate;
273
- const shaking = message.properties.type === 'shake';
315
+ return api;
316
+ };
274
317
 
275
- const isDirectChild = content.parent.id === id;
276
- if (isDirectChild) {
277
- parent.executionId = executionId;
278
- } else {
279
- content.parent = pushParent(parent, {id, type, executionId});
280
- }
318
+ proto._start = function start() {
319
+ if (this[elementsSymbol].children.length === 0) {
320
+ return this._complete('completed');
321
+ }
281
322
 
282
- if (delegate) delegate = onDelegateEvent(message);
323
+ this[statusSymbol] = 'start';
283
324
 
284
- broker.publish('event', routingKey, content, {...message.properties, delegate, mandatory: false});
285
- if (shaking) return onShookEnd(message);
286
- if (!isDirectChild) return;
287
- if (content.isAssociation) return;
325
+ const executeContent = {...this[executeMessageSymbol].content, state: this.status};
288
326
 
289
- switch (routingKey) {
290
- case 'process.terminate':
291
- return activityQ.queueMessage({routingKey: 'execution.terminate'}, cloneContent(content), {type: 'terminate', persistent: true});
292
- case 'activity.stop':
293
- return;
294
- }
327
+ this.broker.publish(this._exchangeName, 'execute.start', cloneContent(executeContent));
295
328
 
296
- activityQ.queueMessage(message.fields, cloneContent(content), {persistent: true, ...message.properties});
297
- }
329
+ const {startActivities, postponed, detachedActivities} = this[elementsSymbol];
330
+ if (startActivities.length > 1) {
331
+ for (const a of startActivities) a.shake();
298
332
  }
299
333
 
300
- function deactivate() {
301
- broker.cancel(`_process-api-consumer-${executionId}`);
302
- broker.cancel(`_process-activity-${executionId}`);
303
-
304
- children.forEach((activity) => {
305
- if (activity.placeholder) return;
306
- activity.broker.cancel('_process-activity-consumer');
307
- activity.deactivate();
334
+ for (const a of startActivities) a.init();
335
+ for (const a of startActivities) a.run();
336
+
337
+ postponed.splice(0);
338
+ detachedActivities.splice(0);
339
+ this[activityQSymbol].assertConsumer(this[messageHandlersSymbol].onChildMessage, {
340
+ prefetch: 1000,
341
+ consumerTag: `_process-activity-${this.executionId}`,
342
+ });
343
+ };
344
+
345
+ proto._activate = function activate() {
346
+ const {onApiMessage, onMessageFlowEvent, onActivityEvent} = this[messageHandlersSymbol];
347
+
348
+ this.broker.subscribeTmp('api', '#', onApiMessage, {
349
+ noAck: true,
350
+ consumerTag: `_process-api-consumer-${this.executionId}`,
351
+ priority: 200,
352
+ });
353
+
354
+ const {outboundMessageFlows, flows, associations, startActivities, triggeredByEvent, children} = this[elementsSymbol];
355
+
356
+ for (const flow of outboundMessageFlows) {
357
+ flow.activate();
358
+ flow.broker.subscribeTmp('event', '#', onMessageFlowEvent, {
359
+ consumerTag: '_process-message-consumer',
360
+ noAck: true,
361
+ priority: 200,
308
362
  });
363
+ }
309
364
 
310
- flows.forEach((flow) => {
311
- flow.broker.cancel('_process-flow-controller');
365
+ for (const flow of flows) {
366
+ flow.broker.subscribeTmp('event', '#', onActivityEvent, {
367
+ consumerTag: '_process-flow-controller',
368
+ noAck: true,
369
+ priority: 200,
312
370
  });
371
+ }
313
372
 
314
- associations.forEach((association) => {
315
- association.broker.cancel('_process-association-controller');
373
+ for (const association of associations) {
374
+ association.broker.subscribeTmp('event', '#', onActivityEvent, {
375
+ consumerTag: '_process-association-controller',
376
+ noAck: true,
377
+ priority: 200,
316
378
  });
379
+ }
317
380
 
318
- outboundMessageFlows.forEach((flow) => {
319
- flow.deactivate();
320
- flow.broker.cancel('_process-message-consumer');
321
- });
381
+ startActivities.splice(0);
382
+ triggeredByEvent.splice(0);
322
383
 
323
- activated = false;
384
+ for (const activity of children) {
385
+ if (activity.placeholder) continue;
386
+ activity.activate(this);
387
+ activity.broker.subscribeTmp('event', '#', onActivityEvent, {
388
+ noAck: true,
389
+ consumerTag: '_process-activity-consumer',
390
+ priority: 200,
391
+ });
392
+ if (activity.isStart) startActivities.push(activity);
393
+ if (activity.triggeredByEvent) triggeredByEvent.push(activity);
324
394
  }
325
395
 
326
- function onDelegateEvent(message) {
327
- const eventType = message.properties.type;
328
- let delegate = true;
396
+ this[activatedSymbol] = true;
397
+ };
329
398
 
330
- const content = message.content;
331
- logger.debug(`<${executionName}> delegate`, eventType, content.message && content.message.id ? `event with id <${content.message.id}>` : 'anonymous event');
399
+ proto._deactivate = function deactivate() {
400
+ const broker = this.broker;
401
+ const executionId = this.executionId;
402
+ broker.cancel(`_process-api-consumer-${executionId}`);
403
+ broker.cancel(`_process-activity-${executionId}`);
332
404
 
333
- triggeredByEventActivities.forEach((activity) => {
334
- if (activity.getStartActivities({referenceId: content.message && content.message.id, referenceType: eventType}).length) {
335
- delegate = false;
336
- activity.run(content.message);
337
- }
338
- });
405
+ const {children, flows, associations, outboundMessageFlows} = this[elementsSymbol];
339
406
 
340
- getApi().sendApiMessage(eventType, content, {delegate: true});
407
+ for (const activity of children) {
408
+ if (activity.placeholder) continue;
409
+ activity.broker.cancel('_process-activity-consumer');
410
+ activity.deactivate();
411
+ }
341
412
 
342
- return delegate;
413
+ for (const flow of flows) {
414
+ flow.broker.cancel('_process-flow-controller');
343
415
  }
344
416
 
345
- function onMessageFlowEvent(routingKey, message) {
346
- broker.publish('message', routingKey, cloneContent(message.content), message.properties);
417
+ for (const association of associations) {
418
+ association.broker.cancel('_process-association-controller');
347
419
  }
348
420
 
349
- function onChildMessage(routingKey, message) {
350
- const content = message.content;
351
- const isRedelivered = message.fields.redelivered;
352
- const {id: childId, type: activityType, isEnd} = content;
353
- const {persistent} = message.properties;
421
+ for (const flow of outboundMessageFlows) {
422
+ flow.deactivate();
423
+ flow.broker.cancel('_process-message-consumer');
424
+ }
354
425
 
355
- if (isRedelivered && persistent === false) return message.ack();
426
+ this[activatedSymbol] = false;
427
+ };
356
428
 
357
- switch (routingKey) {
358
- case 'execution.stop':
359
- message.ack();
360
- return stopExecution();
361
- case 'execution.terminate':
362
- message.ack();
363
- return terminate(message);
364
- case 'execution.discard':
365
- message.ack();
366
- return onDiscard(message);
367
- case 'activity.compensation.end':
368
- case 'flow.looped':
369
- case 'activity.leave':
370
- return onChildCompleted();
371
- }
429
+ proto._onDelegateEvent = function onDelegateEvent(message) {
430
+ const eventType = message.properties.type;
431
+ let delegate = true;
372
432
 
373
- stateChangeMessage(true);
433
+ const content = message.content;
434
+ if (content.message && content.message.id) {
435
+ this._debug(`delegate ${eventType} event with id <${content.message.id}>`);
436
+ } else {
437
+ this._debug(`delegate ${eventType} anonymous event`);
438
+ }
374
439
 
375
- switch (routingKey) {
376
- case 'activity.detach': {
377
- detachedActivities.push(cloneMessage(message));
378
- break;
379
- }
380
- case 'activity.discard':
381
- case 'activity.compensation.start':
382
- case 'activity.enter': {
383
- status = 'executing';
384
- popInbound();
385
- break;
386
- }
387
- case 'flow.error':
388
- case 'activity.error': {
389
- if (isEventCaught()) {
390
- logger.debug(`<${executionName}> error was caught`);
391
- break;
392
- }
393
- complete('error', {error: content.error});
394
- break;
395
- }
440
+ for (const activity of this[elementsSymbol].triggeredByEvent) {
441
+ if (activity.getStartActivities({referenceId: content.message && content.message.id, referenceType: eventType}).length) {
442
+ delegate = false;
443
+ activity.run(content.message);
396
444
  }
445
+ }
397
446
 
398
- function stateChangeMessage(postponeMessage = true) {
399
- const previousMsg = popPostponed(content);
400
- if (previousMsg) previousMsg.ack();
401
- if (postponeMessage) postponed.push(message);
402
- }
447
+ this.getApi().sendApiMessage(eventType, content, {delegate: true});
403
448
 
404
- function popInbound() {
405
- if (!content.inbound) return;
449
+ return delegate;
450
+ };
406
451
 
407
- content.inbound.forEach((trigger) => {
408
- if (!trigger.isSequenceFlow) return;
409
- const msg = popPostponed(trigger, postponed);
410
- if (msg) msg.ack();
411
- });
412
- }
452
+ proto._onMessageFlowEvent = function onMessageFlowEvent(routingKey, message) {
453
+ this.broker.publish('message', routingKey, cloneContent(message.content), message.properties);
454
+ };
413
455
 
414
- function popPostponed(byContent) {
415
- const postponedIdx = postponed.findIndex((msg) => {
416
- if (msg.content.isSequenceFlow) return msg.content.sequenceId === byContent.sequenceId;
417
- return msg.content.executionId === byContent.executionId;
418
- });
456
+ proto._onActivityEvent = function onActivityEvent(routingKey, message) {
457
+ if (message.fields.redelivered && message.properties.persistent === false) return;
419
458
 
420
- let postponedMsg;
421
- if (postponedIdx > -1) {
422
- postponedMsg = postponed.splice(postponedIdx, 1)[0];
423
- }
459
+ const content = message.content;
460
+ const parent = content.parent = content.parent || {};
461
+ let delegate = message.properties.delegate;
462
+ const shaking = message.properties.type === 'shake';
424
463
 
425
- const detachedIdx = detachedActivities.findIndex((msg) => msg.content.executionId === byContent.executionId);
426
- if (detachedIdx > -1) detachedActivities.splice(detachedIdx, 1);
464
+ const isDirectChild = content.parent.id === this.id;
465
+ if (isDirectChild) {
466
+ parent.executionId = this.executionId;
467
+ } else {
468
+ content.parent = pushParent(parent, {id: this.id, type: this.type, executionId: this.executionId});
469
+ }
427
470
 
428
- return postponedMsg;
429
- }
471
+ if (delegate) delegate = this._onDelegateEvent(message);
430
472
 
431
- function onChildCompleted() {
432
- stateChangeMessage(false);
433
- if (isRedelivered) return message.ack();
473
+ this.broker.publish('event', routingKey, content, {...message.properties, delegate, mandatory: false});
474
+ if (shaking) return this._onShookEnd(message);
475
+ if (!isDirectChild) return;
476
+ if (content.isAssociation) return;
434
477
 
435
- logger.debug(`<${executionName}> left <${childId}> (${activityType}), pending runs ${postponed.length}`, postponed.map((a) => a.content.id));
478
+ switch (routingKey) {
479
+ case 'process.terminate':
480
+ return this[activityQSymbol].queueMessage({routingKey: 'execution.terminate'}, cloneContent(content), {type: 'terminate', persistent: true});
481
+ case 'activity.stop':
482
+ return;
483
+ }
436
484
 
437
- const postponedLength = postponed.length;
438
- if (!postponedLength) {
439
- message.ack();
440
- return complete('completed');
441
- } else if (postponedLength === detachedActivities.length) {
442
- getPostponed().forEach((api) => api.discard());
443
- } else if (isEnd && startActivities.length) {
444
- discardPostponedIfNecessary();
445
- }
446
- }
485
+ this[activityQSymbol].queueMessage(message.fields, cloneContent(content), {persistent: true, ...message.properties});
486
+ };
487
+
488
+ proto._onChildMessage = function onChildMessage(routingKey, message) {
489
+ if (message.fields.redelivered && message.properties.persistent === false) return message.ack();
490
+
491
+ const content = message.content;
492
+
493
+ switch (routingKey) {
494
+ case 'execution.stop':
495
+ message.ack();
496
+ return this._stopExecution(message);
497
+ case 'execution.terminate':
498
+ message.ack();
499
+ return this._terminate(message);
500
+ case 'execution.discard':
501
+ message.ack();
502
+ return this._onDiscard(message);
503
+ case 'activity.compensation.end':
504
+ case 'flow.looped':
505
+ case 'activity.leave':
506
+ return this._onChildCompleted(message);
507
+ }
447
508
 
448
- function discardPostponedIfNecessary() {
449
- for (const p of postponed) {
450
- const postponedId = p.content.id;
451
- const startSequence = startSequences[postponedId];
452
- if (startSequence) {
453
- if (startSequence.content.sequence.some(({id: sid}) => sid === childId)) {
454
- getApi(p).discard();
455
- }
456
- }
457
- }
458
- }
509
+ this._stateChangeMessage(message, true);
459
510
 
460
- function stopExecution() {
461
- if (stopped) return;
462
- logger.debug(`<${executionName}> stop process execution (stop child executions ${postponed.length})`);
463
- getPostponed().forEach((api) => {
464
- api.stop();
465
- });
466
- deactivate();
467
- stopped = true;
468
- return broker.publish(exchangeName, `execution.stopped.${executionId}`, {
469
- ...stateMessage.content,
470
- ...content,
471
- }, {type: 'stopped', persistent: false});
511
+ switch (routingKey) {
512
+ case 'activity.detach': {
513
+ this[elementsSymbol].detachedActivities.push(cloneMessage(message));
514
+ break;
472
515
  }
516
+ case 'activity.discard':
517
+ case 'activity.compensation.start':
518
+ case 'activity.enter': {
519
+ this[statusSymbol] = 'executing';
520
+ if (!content.inbound) break;
521
+
522
+ for (const inbound of content.inbound) {
523
+ if (!inbound.isSequenceFlow) continue;
524
+ const inboundMessage = this._popPostponed(inbound);
525
+ if (inboundMessage) inboundMessage.ack();
526
+ }
473
527
 
474
- function onDiscard() {
475
- deactivate();
476
- const running = postponed.splice(0);
477
- logger.debug(`<${executionName}> discard process execution (discard child executions ${running.length})`);
478
-
479
- getSequenceFlows().forEach((flow) => {
480
- flow.stop();
481
- });
482
-
483
- running.forEach((msg) => {
484
- getApi(msg).discard();
485
- });
486
-
487
- activityQ.purge();
488
- return complete('discard');
528
+ break;
489
529
  }
490
-
491
- function isEventCaught() {
492
- return postponed.find((msg) => {
530
+ case 'flow.error':
531
+ case 'activity.error': {
532
+ const eventCaughtBy = this[elementsSymbol].postponed.find((msg) => {
493
533
  if (msg.fields.routingKey !== 'activity.catch') return;
494
534
  return msg.content.source && msg.content.source.executionId === content.executionId;
495
535
  });
536
+ if (eventCaughtBy) {
537
+ return this._debug('error was caught');
538
+ }
539
+ return this._complete('error', {error: content.error});
496
540
  }
497
541
  }
542
+ };
498
543
 
499
- function onApiMessage(routingKey, message) {
500
- if (message.properties.delegate) {
501
- return delegateApiMessage();
502
- }
544
+ proto._stateChangeMessage = function stateChangeMessage(message, postponeMessage) {
545
+ const previousMsg = this._popPostponed(message.content);
546
+ if (previousMsg) previousMsg.ack();
547
+ if (postponeMessage) this[elementsSymbol].postponed.push(message);
548
+ };
503
549
 
504
- if (id !== message.content.id) {
505
- const child = getActivityById(message.content.id);
506
- if (!child) return null;
507
- return child.broker.publish('api', routingKey, message.content, message.properties);
508
- }
550
+ proto._popPostponed = function popPostponed(byContent) {
551
+ const {postponed, detachedActivities} = this[elementsSymbol];
509
552
 
510
- if (executionId !== message.content.executionId) return;
553
+ const postponedIdx = postponed.findIndex((msg) => {
554
+ if (msg.content.isSequenceFlow) return msg.content.sequenceId === byContent.sequenceId;
555
+ return msg.content.executionId === byContent.executionId;
556
+ });
511
557
 
512
- switch (message.properties.type) {
513
- case 'discard':
514
- return discard(message);
515
- case 'stop':
516
- activityQ.queueMessage({routingKey: 'execution.stop'}, cloneContent(message.content), {persistent: false});
517
- break;
518
- }
519
-
520
- function delegateApiMessage() {
521
- const {correlationId} = message.properties || getUniqueId(executionId);
522
- logger.debug(`<${executionName}> delegate api`, routingKey, `message to children, with correlationId <${correlationId}>`);
523
-
524
- let consumed = false;
525
- broker.subscribeTmp('event', 'activity.consumed', (_, msg) => {
526
- if (msg.properties.correlationId === correlationId) {
527
- consumed = true;
528
- logger.debug(`<${executionName}> delegated api message was consumed by`, msg.content ? msg.content.executionId : 'unknown');
529
- }
530
- }, {consumerTag: `_ct-delegate-${correlationId}`, noAck: true});
531
-
532
- for (const child of children) {
533
- if (child.placeholder) continue;
534
- child.broker.publish('api', routingKey, cloneContent(message.content), message.properties);
535
- if (consumed) break;
536
- }
537
-
538
- broker.cancel(`_ct-delegate-${correlationId}`);
539
- }
558
+ let postponedMsg;
559
+ if (postponedIdx > -1) {
560
+ postponedMsg = postponed.splice(postponedIdx, 1)[0];
540
561
  }
541
562
 
542
- function getPostponed(filterFn) {
543
- return postponed.slice().reduce((result, p) => {
544
- const api = getApi(p);
545
- if (api) {
546
- if (filterFn && !filterFn(api)) return result;
547
- result.push(api);
548
- }
549
- return result;
550
- }, []);
551
- }
563
+ const detachedIdx = detachedActivities.findIndex((msg) => msg.content.executionId === byContent.executionId);
564
+ if (detachedIdx > -1) detachedActivities.splice(detachedIdx, 1);
552
565
 
553
- function complete(completionType, content = {}) {
554
- deactivate();
555
- logger.debug(`<${executionName}> process execution ${completionType}`);
556
- completed = true;
557
- if (status !== 'terminated') status = completionType;
558
- broker.deleteQueue(activityQ.name);
566
+ return postponedMsg;
567
+ };
559
568
 
560
- return broker.publish(exchangeName, `execution.${completionType}.${executionId}`, {
561
- ...stateMessage.content,
562
- output: environment.output,
563
- ...content,
564
- state: completionType,
565
- }, {type: completionType, mandatory: completionType === 'error'});
566
- }
569
+ proto._onChildCompleted = function onChildCompleted(message) {
570
+ this._stateChangeMessage(message, false);
571
+ if (message.fields.redelivered) return message.ack();
567
572
 
568
- function discard() {
569
- status = 'discard';
570
- return activityQ.queueMessage({routingKey: 'execution.discard'}, {
571
- id,
572
- type,
573
- executionId,
574
- }, {type: 'discard'});
575
- }
573
+ const {id, type, isEnd} = message.content;
576
574
 
577
- function terminate(message) {
578
- status = 'terminated';
579
- logger.debug(`<${executionName}> terminating process execution`);
575
+ const {postponed, detachedActivities, startActivities} = this[elementsSymbol];
576
+ const postponedCount = postponed.length;
580
577
 
581
- const running = postponed.splice(0);
582
- getSequenceFlows().forEach((flow) => {
583
- flow.stop();
584
- });
578
+ if (!postponedCount) {
579
+ this._debug(`left <${id}> (${type}), pending runs ${postponedCount}`);
580
+ message.ack();
581
+ return this._complete('completed');
582
+ }
585
583
 
586
- running.forEach((msg) => {
587
- const {id: postponedId, isSequenceFlow} = msg.content;
588
- if (postponedId === message.content.id) return;
589
- if (isSequenceFlow) return;
590
- getApi(msg).stop();
591
- msg.ack();
592
- });
584
+ this._debug(`left <${id}> (${type}), pending runs ${postponedCount}, ${postponed.map((a) => a.content.id).join(',')}`);
593
585
 
594
- activityQ.purge();
586
+ if (postponedCount === detachedActivities.length) {
587
+ for (const api of this.getPostponed()) api.discard();
588
+ return;
595
589
  }
596
590
 
597
- function getState() {
598
- return {
599
- executionId,
600
- stopped,
601
- completed,
602
- status,
603
- children: children.reduce((result, activity) => {
604
- if (activity.placeholder) return result;
605
- result.push(activity.getState());
606
- return result;
607
- }, []),
608
- flows: flows.map((f) => f.getState()),
609
- messageFlows: outboundMessageFlows.map((f) => f.getState()),
610
- associations: associations.map((f) => f.getState()),
611
- };
591
+ if (isEnd && startActivities.length) {
592
+ const startSequences = this[elementsSymbol].startSequences;
593
+ for (const msg of postponed) {
594
+ const postponedId = msg.content.id;
595
+ const startSequence = startSequences[postponedId];
596
+ if (startSequence) {
597
+ if (startSequence.content.sequence.some(({id: sid}) => sid === id)) {
598
+ this._getChildApi(msg).discard();
599
+ }
600
+ }
601
+ }
612
602
  }
613
-
614
- function getActivities() {
615
- return children.slice();
603
+ };
604
+
605
+ proto._stopExecution = function stopExecution(message) {
606
+ if (this[stoppedSymbol]) return;
607
+ const postponedCount = this.postponedCount;
608
+ this._debug(`stop process execution (stop child executions ${postponedCount})`);
609
+ if (postponedCount) {
610
+ for (const api of this.getPostponed()) api.stop();
616
611
  }
612
+ this._deactivate();
613
+ this[stoppedSymbol] = true;
614
+ return this.broker.publish(this._exchangeName, `execution.stopped.${this.executionId}`, {
615
+ ...this[executeMessageSymbol].content,
616
+ ...(message && message.content),
617
+ }, {type: 'stopped', persistent: false});
618
+ };
619
+
620
+ proto._onDiscard = function onDiscard() {
621
+ this._deactivate();
622
+ const running = this[elementsSymbol].postponed.splice(0);
623
+ this._debug(`discard process execution (discard child executions ${running.length})`);
624
+
625
+ for (const flow of this.getSequenceFlows()) flow.stop();
626
+ for (const msg of running) this._getChildApi(msg).discard();
627
+
628
+ this[activityQSymbol].purge();
629
+ return this._complete('discard');
630
+ };
631
+
632
+ proto._onApiMessage = function onApiMessage(routingKey, message) {
633
+ const executionId = this.executionId;
634
+ const broker = this.broker;
635
+ if (message.properties.delegate) {
636
+ const {correlationId} = message.properties || getUniqueId(executionId);
637
+ this._debug(`delegate api ${routingKey} message to children, with correlationId <${correlationId}>`);
638
+
639
+ let consumed = false;
640
+ broker.subscribeTmp('event', 'activity.consumed', (_, msg) => {
641
+ if (msg.properties.correlationId === correlationId) {
642
+ consumed = true;
643
+ this._debug(`delegated api message was consumed by ${msg.content ? msg.content.executionId : 'unknown'}`);
644
+ }
645
+ }, {consumerTag: `_ct-delegate-${correlationId}`, noAck: true});
617
646
 
618
- function getActivityById(activityId) {
619
- return children.find((child) => child.id === activityId);
620
- }
647
+ for (const child of this[elementsSymbol].children) {
648
+ if (child.placeholder) continue;
649
+ child.broker.publish('api', routingKey, cloneContent(message.content), message.properties);
650
+ if (consumed) break;
651
+ }
621
652
 
622
- function getFlowById(flowId) {
623
- return flows.find((f) => f.id === flowId);
653
+ return broker.cancel(`_ct-delegate-${correlationId}`);
624
654
  }
625
655
 
626
- function getAssociationById(associationId) {
627
- return associations.find((a) => a.id === associationId);
656
+ if (this.id !== message.content.id) {
657
+ const child = this.getActivityById(message.content.id);
658
+ if (!child) return null;
659
+ return child.broker.publish('api', routingKey, message.content, message.properties);
628
660
  }
629
661
 
630
- function getMessageFlowById(flowId) {
631
- return outboundMessageFlows.find((f) => f.id === flowId);
632
- }
662
+ if (this.executionId !== message.content.executionId) return;
633
663
 
634
- function getChildById(childId) {
635
- return getActivityById(childId) || getFlowById(childId);
664
+ switch (message.properties.type) {
665
+ case 'discard':
666
+ return this.discard(message);
667
+ case 'stop':
668
+ this[activityQSymbol].queueMessage({routingKey: 'execution.stop'}, cloneContent(message.content), {persistent: false});
669
+ break;
636
670
  }
637
-
638
- function getSequenceFlows() {
639
- return flows.slice();
671
+ };
672
+
673
+ proto._complete = function complete(completionType, content) {
674
+ this._deactivate();
675
+ this._debug(`process execution ${completionType}`);
676
+ this[completedSymbol] = true;
677
+ if (this.status !== 'terminated') this[statusSymbol] = completionType;
678
+ const broker = this.broker;
679
+ this[activityQSymbol].delete();
680
+
681
+ return broker.publish(this._exchangeName, `execution.${completionType}.${this.executionId}`, cloneContent(this[executeMessageSymbol].content, {
682
+ output: {...this.environment.output},
683
+ ...content,
684
+ state: completionType,
685
+ }), {type: completionType, mandatory: completionType === 'error'});
686
+ };
687
+
688
+ proto._terminate = function terminate(message) {
689
+ this[statusSymbol] = 'terminated';
690
+ this._debug('terminating process execution');
691
+
692
+ const running = this[elementsSymbol].postponed.splice(0);
693
+ for (const flow of this.getSequenceFlows()) flow.stop();
694
+
695
+ for (const msg of running) {
696
+ const {id: postponedId, isSequenceFlow} = msg.content;
697
+ if (postponedId === message.content.id) continue;
698
+ if (isSequenceFlow) continue;
699
+ this._getChildApi(msg).stop();
700
+ msg.ack();
640
701
  }
641
702
 
642
- function getApi(message) {
643
- if (!message) return ProcessApi(broker, stateMessage);
703
+ this[activityQSymbol].purge();
704
+ };
644
705
 
645
- const content = message.content;
646
- if (content.executionId !== executionId) {
647
- return getChildApi(message);
648
- }
649
-
650
- const api = ProcessApi(broker, message);
706
+ proto._getFlowById = function getFlowById(flowId) {
707
+ return this[elementsSymbol].flows.find((f) => f.id === flowId);
708
+ };
651
709
 
652
- api.getExecuting = function getExecuting() {
653
- return postponed.reduce((result, msg) => {
654
- if (msg.content.executionId === content.executionId) return result;
655
- result.push(getApi(msg));
656
- return result;
657
- }, []);
658
- };
710
+ proto._getAssociationById = function getAssociationById(associationId) {
711
+ return this[elementsSymbol].associations.find((a) => a.id === associationId);
712
+ };
659
713
 
660
- return api;
661
- }
714
+ proto._getMessageFlowById = function getMessageFlowById(flowId) {
715
+ return this[elementsSymbol].outboundMessageFlows.find((f) => f.id === flowId);
716
+ };
662
717
 
663
- function getChildApi(message) {
664
- const content = message.content;
718
+ proto._getChildById = function getChildById(childId) {
719
+ return this.getActivityById(childId) || this._getFlowById(childId);
720
+ };
665
721
 
666
- let api = getApiByChildId(content.id);
667
- if (api) return api;
722
+ proto._getChildApi = function getChildApi(message) {
723
+ const content = message.content;
668
724
 
669
- if (!content.parent) return;
725
+ let child = this._getChildById(content.id);
726
+ if (child) return child.getApi(message);
670
727
 
671
- api = getApiByChildId(content.parent.id);
672
- if (api) return api;
728
+ if (!content.parent) return;
673
729
 
674
- if (!content.parent.path) return;
730
+ child = this._getChildById(content.parent.id);
731
+ if (child) return child.getApi(message);
675
732
 
676
- for (let i = 0; i < content.parent.path.length; i++) {
677
- api = getApiByChildId(content.parent.path[i].id);
678
- if (api) return api;
679
- }
733
+ if (!content.parent.path) return;
680
734
 
681
- function getApiByChildId(childId) {
682
- const child = getChildById(childId);
683
- if (!child) return;
684
- return child.getApi(message);
685
- }
735
+ for (const pp of content.parent.path) {
736
+ child = this._getChildById(pp.id, message);
737
+ if (child) return child.getApi(message);
686
738
  }
739
+ };
687
740
 
688
- function onShookEnd(message) {
689
- const routingKey = message.fields.routingKey;
690
- if (routingKey !== 'activity.shake.end') return;
691
- startSequences[message.content.id] = cloneMessage(message);
692
- }
741
+ proto._onShookEnd = function onShookEnd(message) {
742
+ const routingKey = message.fields.routingKey;
743
+ if (routingKey !== 'activity.shake.end') return;
744
+ this[elementsSymbol].startSequences[message.content.id] = cloneMessage(message);
745
+ };
693
746
 
694
- function prepare() {
695
- executionName = `${executionId} (${id})`;
696
- }
697
- }
747
+ proto._debug = function debugMessage(logMessage) {
748
+ this[parentSymbol].logger.debug(`<${this.executionId} (${this.id})> ${logMessage}`);
749
+ };