bpmn-elements 5.1.3 → 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 (119) hide show
  1. package/CHANGELOG.md +322 -0
  2. package/README.md +9 -3
  3. package/dist/index.js +71 -39
  4. package/dist/src/Api.js +77 -76
  5. package/dist/src/Context.js +169 -164
  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/Timers.js +4 -6
  12. package/dist/src/activity/Activity.js +1108 -901
  13. package/dist/src/activity/ActivityExecution.js +342 -297
  14. package/dist/src/activity/Dummy.js +3 -3
  15. package/dist/src/definition/Definition.js +498 -444
  16. package/dist/src/definition/DefinitionExecution.js +722 -409
  17. package/dist/src/error/Errors.js +17 -7
  18. package/dist/src/eventDefinitions/CancelEventDefinition.js +190 -150
  19. package/dist/src/eventDefinitions/CompensateEventDefinition.js +194 -161
  20. package/dist/src/eventDefinitions/ConditionalEventDefinition.js +197 -135
  21. package/dist/src/eventDefinitions/ErrorEventDefinition.js +207 -165
  22. package/dist/src/eventDefinitions/EscalationEventDefinition.js +175 -141
  23. package/dist/src/eventDefinitions/EventDefinitionExecution.js +157 -129
  24. package/dist/src/eventDefinitions/LinkEventDefinition.js +174 -149
  25. package/dist/src/eventDefinitions/MessageEventDefinition.js +213 -176
  26. package/dist/src/eventDefinitions/SignalEventDefinition.js +203 -161
  27. package/dist/src/eventDefinitions/TerminateEventDefinition.js +21 -23
  28. package/dist/src/eventDefinitions/TimerEventDefinition.js +243 -228
  29. package/dist/src/events/BoundaryEvent.js +180 -144
  30. package/dist/src/events/EndEvent.js +18 -23
  31. package/dist/src/events/IntermediateCatchEvent.js +44 -58
  32. package/dist/src/events/IntermediateThrowEvent.js +18 -23
  33. package/dist/src/events/StartEvent.js +109 -94
  34. package/dist/src/flows/Association.js +94 -101
  35. package/dist/src/flows/MessageFlow.js +86 -103
  36. package/dist/src/flows/SequenceFlow.js +172 -184
  37. package/dist/src/gateways/EventBasedGateway.js +88 -84
  38. package/dist/src/gateways/ExclusiveGateway.js +13 -16
  39. package/dist/src/gateways/InclusiveGateway.js +11 -14
  40. package/dist/src/gateways/ParallelGateway.js +11 -14
  41. package/dist/src/getPropertyValue.js +34 -34
  42. package/dist/src/io/BpmnIO.js +31 -0
  43. package/dist/src/io/EnvironmentDataObject.js +33 -29
  44. package/dist/src/io/EnvironmentDataStore.js +52 -0
  45. package/dist/src/io/EnvironmentDataStoreReference.js +52 -0
  46. package/dist/src/io/InputOutputSpecification.js +177 -168
  47. package/dist/src/io/Properties.js +252 -0
  48. package/dist/src/messageHelper.js +1 -1
  49. package/dist/src/process/Process.js +433 -359
  50. package/dist/src/process/ProcessExecution.js +744 -645
  51. package/dist/src/shared.js +3 -6
  52. package/dist/src/tasks/CallActivity.js +160 -0
  53. package/dist/src/tasks/LoopCharacteristics.js +309 -330
  54. package/dist/src/tasks/ReceiveTask.js +233 -182
  55. package/dist/src/tasks/ScriptTask.js +35 -41
  56. package/dist/src/tasks/ServiceImplementation.js +13 -20
  57. package/dist/src/tasks/ServiceTask.js +82 -75
  58. package/dist/src/tasks/SignalTask.js +97 -93
  59. package/dist/src/tasks/StandardLoopCharacteristics.js +1 -1
  60. package/dist/src/tasks/SubProcess.js +195 -175
  61. package/dist/src/tasks/Task.js +17 -19
  62. package/index.js +8 -0
  63. package/package.json +16 -15
  64. package/src/Api.js +65 -59
  65. package/src/Context.js +142 -132
  66. package/src/Environment.js +88 -100
  67. package/src/EventBroker.js +67 -68
  68. package/src/ExtensionsMapper.js +2 -2
  69. package/src/MessageFormatter.js +132 -74
  70. package/src/Timers.js +4 -4
  71. package/src/activity/Activity.js +916 -757
  72. package/src/activity/ActivityExecution.js +293 -247
  73. package/src/activity/Dummy.js +2 -2
  74. package/src/definition/Definition.js +436 -401
  75. package/src/definition/DefinitionExecution.js +603 -343
  76. package/src/error/Errors.js +11 -6
  77. package/src/eventDefinitions/CancelEventDefinition.js +164 -121
  78. package/src/eventDefinitions/CompensateEventDefinition.js +158 -124
  79. package/src/eventDefinitions/ConditionalEventDefinition.js +147 -104
  80. package/src/eventDefinitions/ErrorEventDefinition.js +190 -131
  81. package/src/eventDefinitions/EscalationEventDefinition.js +139 -101
  82. package/src/eventDefinitions/EventDefinitionExecution.js +127 -95
  83. package/src/eventDefinitions/LinkEventDefinition.js +160 -129
  84. package/src/eventDefinitions/MessageEventDefinition.js +178 -121
  85. package/src/eventDefinitions/SignalEventDefinition.js +162 -106
  86. package/src/eventDefinitions/TerminateEventDefinition.js +19 -19
  87. package/src/eventDefinitions/TimerEventDefinition.js +202 -167
  88. package/src/events/BoundaryEvent.js +156 -115
  89. package/src/events/EndEvent.js +15 -18
  90. package/src/events/IntermediateCatchEvent.js +40 -44
  91. package/src/events/IntermediateThrowEvent.js +15 -18
  92. package/src/events/StartEvent.js +84 -50
  93. package/src/flows/Association.js +98 -113
  94. package/src/flows/MessageFlow.js +81 -97
  95. package/src/flows/SequenceFlow.js +145 -163
  96. package/src/gateways/EventBasedGateway.js +75 -68
  97. package/src/gateways/ExclusiveGateway.js +8 -13
  98. package/src/gateways/InclusiveGateway.js +8 -13
  99. package/src/gateways/ParallelGateway.js +8 -13
  100. package/src/getPropertyValue.js +34 -33
  101. package/src/io/BpmnIO.js +20 -0
  102. package/src/io/EnvironmentDataObject.js +29 -18
  103. package/src/io/EnvironmentDataStore.js +33 -0
  104. package/src/io/EnvironmentDataStoreReference.js +33 -0
  105. package/src/io/InputOutputSpecification.js +154 -157
  106. package/src/io/Properties.js +199 -0
  107. package/src/process/Process.js +374 -333
  108. package/src/process/ProcessExecution.js +606 -554
  109. package/src/shared.js +1 -5
  110. package/src/tasks/CallActivity.js +130 -0
  111. package/src/tasks/LoopCharacteristics.js +290 -289
  112. package/src/tasks/ReceiveTask.js +174 -107
  113. package/src/tasks/ScriptTask.js +27 -30
  114. package/src/tasks/ServiceImplementation.js +13 -18
  115. package/src/tasks/ServiceTask.js +67 -60
  116. package/src/tasks/SignalTask.js +77 -52
  117. package/src/tasks/StandardLoopCharacteristics.js +1 -1
  118. package/src/tasks/SubProcess.js +184 -157
  119. package/src/tasks/Task.js +15 -19
@@ -1,4 +1,5 @@
1
1
  import ActivityExecution from './ActivityExecution';
2
+ import BpmnIO from '../io/BpmnIO';
2
3
  import {brokerSafeId, getUniqueId} from '../shared';
3
4
  import {ActivityApi} from '../Api';
4
5
  import {ActivityBroker} from '../EventBroker';
@@ -6,925 +7,1083 @@ import {Formatter} from '../MessageFormatter';
6
7
  import {cloneContent, cloneParent, cloneMessage} from '../messageHelper';
7
8
  import {makeErrorFromMessage, ActivityError} from '../error/Errors';
8
9
 
9
- export default function Activity(Behaviour, activityDef, context) {
10
- const {id, type = 'activity', name, parent: originalParent = {}, behaviour = {}, isParallelGateway, isSubProcess, triggeredByEvent, isThrowing, isTransaction} = activityDef;
11
- const isForCompensation = behaviour.isForCompensation;
12
-
13
- const parent = cloneParent(originalParent);
14
- const {environment, getInboundSequenceFlows, getOutboundSequenceFlows, getInboundAssociations} = context;
15
-
16
- const logger = environment.Logger(type.toLowerCase());
17
- const {step} = environment.settings;
10
+ const activityDefSymbol = Symbol.for('activityDefinition');
11
+ const bpmnIoSymbol = Symbol.for('bpmnIo');
12
+ const consumingSymbol = Symbol.for('consuming');
13
+ const countersSymbol = Symbol.for('counters');
14
+ const eventDefinitionsSymbol = Symbol.for('eventDefinitions');
15
+ const execSymbol = Symbol.for('exec');
16
+ const executeMessageSymbol = Symbol.for('executeMessage');
17
+ const extensionsSymbol = Symbol.for('extensions');
18
+ const flagsSymbol = Symbol.for('flags');
19
+ const flowsSymbol = Symbol.for('flows');
20
+ const formatterSymbol = Symbol.for('formatter');
21
+ const messageHandlersSymbol = Symbol.for('messageHandlers');
22
+ const stateMessageSymbol = Symbol.for('stateMessage');
23
+
24
+ export default Activity;
25
+
26
+ function Activity(Behaviour, activityDef, context) {
27
+ const {id, type = 'activity', name, behaviour = {}} = activityDef;
28
+ const {attachedTo: attachedToRef, eventDefinitions} = behaviour;
29
+
30
+ this[activityDefSymbol] = activityDef;
31
+ this.id = id;
32
+ this.type = type;
33
+ this.name = name;
34
+ this.behaviour = {...behaviour, eventDefinitions};
35
+ this.Behaviour = Behaviour;
36
+ this.parent = activityDef.parent ? cloneParent(activityDef.parent) : {};
37
+ this.logger = context.environment.Logger(type.toLowerCase());
38
+ this.environment = context.environment;
39
+ this.context = context;
40
+ this[countersSymbol] = {
41
+ taken: 0,
42
+ discarded: 0,
43
+ };
18
44
 
19
- const {attachedTo: attachedToRef, ioSpecification: ioSpecificationDef, eventDefinitions} = behaviour;
20
45
  let attachedToActivity, attachedTo;
21
-
22
46
  if (attachedToRef) {
23
47
  attachedTo = attachedToRef.id;
24
48
  attachedToActivity = context.getActivityById(attachedToRef.id);
25
49
  }
26
50
 
27
- const inboundSequenceFlows = getInboundSequenceFlows(id) || [];
28
- const outboundSequenceFlows = getOutboundSequenceFlows(id) || [];
29
- const inboundAssociations = getInboundAssociations(id) || [];
30
-
31
- const isStart = inboundSequenceFlows.length === 0 && !attachedTo && !triggeredByEvent && !isForCompensation;
32
- const isEnd = outboundSequenceFlows.length === 0;
33
- const isParallelJoin = inboundSequenceFlows.length > 1 && isParallelGateway;
34
- const isMultiInstance = !!behaviour.loopCharacteristics;
51
+ const {broker, on, once, waitFor, emitFatal} = ActivityBroker(this);
35
52
 
36
- let execution, initExecutionId, executionId, stateMessage, status, stopped = false, executeMessage, consumingRunQ;
53
+ this.broker = broker;
54
+ this.on = on;
55
+ this.once = once;
56
+ this.waitFor = waitFor;
57
+ this.emitFatal = emitFatal;
37
58
 
59
+ const inboundSequenceFlows = context.getInboundSequenceFlows(id);
60
+ const inboundAssociations = context.getInboundAssociations(id);
38
61
  const inboundTriggers = attachedToActivity ? [attachedToActivity] : inboundSequenceFlows.slice();
39
- const inboundJoinFlows = [];
40
-
41
- let counters = {
42
- taken: 0,
43
- discarded: 0,
62
+ const outboundSequenceFlows = context.getOutboundSequenceFlows(id);
63
+ const flows = this[flowsSymbol] = {
64
+ inboundSequenceFlows,
65
+ inboundAssociations,
66
+ inboundJoinFlows: [],
67
+ inboundTriggers,
68
+ outboundSequenceFlows,
69
+ outboundEvaluator: new OutboundEvaluator(this, outboundSequenceFlows),
44
70
  };
45
71
 
46
- const activityApi = {
47
- id,
48
- type,
49
- name,
50
- isEnd,
51
- isStart,
52
- isSubProcess,
53
- isThrowing,
72
+ const isForCompensation = !!behaviour.isForCompensation;
73
+ const isParallelJoin = activityDef.isParallelGateway && flows.inboundSequenceFlows.length > 1;
74
+ this[flagsSymbol] = {
75
+ isEnd: flows.outboundSequenceFlows.length === 0,
76
+ isStart: flows.inboundSequenceFlows.length === 0 && !attachedTo && !behaviour.triggeredByEvent && !isForCompensation,
77
+ isSubProcess: activityDef.isSubProcess,
78
+ isMultiInstance: !!behaviour.loopCharacteristics,
54
79
  isForCompensation,
55
- triggeredByEvent,
56
- parent: cloneParent(parent),
57
- behaviour: {...behaviour, eventDefinitions},
58
- attachedTo: attachedToActivity,
59
- environment,
60
- inbound: inboundSequenceFlows,
61
- outbound: outboundSequenceFlows,
62
- get counters() {
63
- return {...counters};
64
- },
65
- get executionId() {
66
- return executionId;
67
- },
68
- get status() {
69
- return status;
70
- },
71
- get stopped() {
72
- return stopped;
73
- },
74
- get isRunning() {
75
- if (!consumingRunQ) return false;
76
- return !!status;
77
- },
78
- Behaviour,
79
- activate,
80
- deactivate,
81
- evaluateOutbound,
82
- logger,
83
- discard,
84
- getApi,
85
- getActivityById,
86
- getState,
87
- init,
88
- recover,
89
- resume,
90
- run,
91
- shake,
92
- stop,
93
- next: step && next,
80
+ attachedTo,
81
+ isTransaction: activityDef.isTransaction,
82
+ isParallelJoin,
83
+ isThrowing: activityDef.isThrowing,
94
84
  };
85
+ this[execSymbol] = {};
95
86
 
96
- const {broker, on, once, waitFor, emitFatal} = ActivityBroker(activityApi);
97
-
98
- activityApi.on = on;
99
- activityApi.once = once;
100
- activityApi.waitFor = waitFor;
101
- activityApi.emitFatal = emitFatal;
102
-
103
- const runQ = broker.getQueue('run-q');
104
- const executionQ = broker.getQueue('execution-q');
105
- const inboundQ = broker.assertQueue('inbound-q', {durable: true, autoDelete: false});
106
-
107
- const formatRunQ = broker.getQueue('format-run-q');
108
- const formatter = Formatter({id, broker, logger}, formatRunQ);
87
+ this[messageHandlersSymbol] = {
88
+ onInbound: isParallelJoin ? this._onJoinInbound.bind(this) : this._onInbound.bind(this),
89
+ onRunMessage: this._onRunMessage.bind(this),
90
+ onApiMessage: this._onApiMessage.bind(this),
91
+ onExecutionMessage: this._onExecutionMessage.bind(this),
92
+ };
109
93
 
94
+ const onInboundEvent = this._onInboundEvent.bind(this);
95
+ broker.assertQueue('inbound-q', {durable: true, autoDelete: false});
110
96
  if (isForCompensation) {
111
- inboundAssociations.forEach((trigger) => {
97
+ for (const trigger of inboundAssociations) {
112
98
  trigger.broker.subscribeTmp('event', '#', onInboundEvent, {noAck: true, consumerTag: `_inbound-${id}`});
113
- });
99
+ }
114
100
  } else {
115
- inboundTriggers.forEach((trigger) => {
101
+ for (const trigger of inboundTriggers) {
116
102
  if (trigger.isSequenceFlow) trigger.broker.subscribeTmp('event', 'flow.#', onInboundEvent, {noAck: true, consumerTag: `_inbound-${id}`});
117
103
  else trigger.broker.subscribeTmp('event', 'activity.#', onInboundEvent, {noAck: true, consumerTag: `_inbound-${id}`});
118
- });
104
+ }
119
105
  }
120
106
 
121
- Object.defineProperty(activityApi, 'broker', {
122
- enumerable: true,
123
- get: () => broker,
124
- });
125
-
126
- Object.defineProperty(activityApi, 'execution', {
127
- enumerable: true,
128
- get: () => execution,
129
- });
130
-
131
- const ioSpecification = ioSpecificationDef && ioSpecificationDef.Behaviour(activityApi, ioSpecificationDef, context);
132
-
133
- const loaedEventDefinitions = eventDefinitions && eventDefinitions.map((ed) => ed.Behaviour(activityApi, ed, context));
134
- Object.defineProperty(activityApi, 'eventDefinitions', {
135
- enumerable: true,
136
- get: () => loaedEventDefinitions,
137
- });
138
-
139
- const extensions = context.loadExtensions(activityApi);
140
- Object.defineProperty(activityApi, 'extensions', {
141
- enumerable: true,
142
- get: () => extensions,
143
- });
144
-
145
- return activityApi;
107
+ this[eventDefinitionsSymbol] = eventDefinitions && eventDefinitions.map((ed) => new ed.Behaviour(this, ed, this.context));
108
+ }
146
109
 
147
- function init(initContent) {
148
- initExecutionId = initExecutionId || getUniqueId(id);
149
- logger.debug(`<${id}> initialized with executionId <${initExecutionId}>`);
150
- publishEvent('init', createMessage({...initContent, executionId: initExecutionId}));
110
+ const proto = Activity.prototype;
111
+
112
+ Object.defineProperty(proto, 'counters', {
113
+ enumerable: true,
114
+ get() {
115
+ return {...this[countersSymbol]};
116
+ },
117
+ });
118
+
119
+ Object.defineProperty(proto, 'execution', {
120
+ enumerable: true,
121
+ get() {
122
+ return this[execSymbol].execution;
123
+ },
124
+ });
125
+
126
+ Object.defineProperty(proto, 'executionId', {
127
+ enumerable: true,
128
+ get() {
129
+ return this[execSymbol].executionId;
130
+ },
131
+ });
132
+
133
+ Object.defineProperty(proto, 'bpmnIo', {
134
+ enumerable: true,
135
+ get() {
136
+ if (bpmnIoSymbol in this) return this[bpmnIoSymbol];
137
+ const bpmnIo = this[bpmnIoSymbol] = new BpmnIO(this, this.context);
138
+ return bpmnIo;
139
+ },
140
+ });
141
+
142
+ Object.defineProperty(proto, 'extensions', {
143
+ enumerable: true,
144
+ get() {
145
+ if (extensionsSymbol in this) return this[extensionsSymbol];
146
+ const extensions = this[extensionsSymbol] = this.context.loadExtensions(this);
147
+ return extensions;
148
+ },
149
+ });
150
+
151
+ Object.defineProperty(proto, 'formatter', {
152
+ enumerable: true,
153
+ get() {
154
+ let formatter = this[formatterSymbol];
155
+ if (formatter) return formatter;
156
+
157
+ const broker = this.broker;
158
+ formatter = this[formatterSymbol] = new Formatter({
159
+ id: this.id,
160
+ broker,
161
+ logger: this.logger,
162
+ }, broker.getQueue('format-run-q'));
163
+ return formatter;
164
+ },
165
+ });
166
+
167
+ Object.defineProperty(proto, 'isRunning', {
168
+ enumerable: true,
169
+ get() {
170
+ if (!this[consumingSymbol]) return false;
171
+ return !!this.status;
172
+ },
173
+ });
174
+
175
+ Object.defineProperty(proto, 'outbound', {
176
+ enumerable: true,
177
+ get() {
178
+ return this[flowsSymbol].outboundSequenceFlows;
179
+ },
180
+ });
181
+
182
+ Object.defineProperty(proto, 'inbound', {
183
+ enumerable: true,
184
+ get() {
185
+ return this[flowsSymbol].inboundSequenceFlows;
186
+ },
187
+ });
188
+
189
+ Object.defineProperty(proto, 'isEnd', {
190
+ enumerable: true,
191
+ get() {
192
+ return this[flagsSymbol].isEnd;
193
+ },
194
+ });
195
+ Object.defineProperty(proto, 'isStart', {
196
+ enumerable: true,
197
+ get() {
198
+ return this[flagsSymbol].isStart;
199
+ },
200
+ });
201
+ Object.defineProperty(proto, 'isSubProcess', {
202
+ enumerable: true,
203
+ get() {
204
+ return this[flagsSymbol].isSubProcess;
205
+ },
206
+ });
207
+
208
+ Object.defineProperty(proto, 'isMultiInstance', {
209
+ enumerable: true,
210
+ get() {
211
+ return this[flagsSymbol].isMultiInstance;
212
+ },
213
+ });
214
+
215
+ Object.defineProperty(proto, 'isThrowing', {
216
+ enumerable: true,
217
+ get() {
218
+ return this[flagsSymbol].isThrowing;
219
+ },
220
+ });
221
+ Object.defineProperty(proto, 'isForCompensation', {
222
+ enumerable: true,
223
+ get() {
224
+ return this[flagsSymbol].isForCompensation;
225
+ },
226
+ });
227
+ Object.defineProperty(proto, 'triggeredByEvent', {
228
+ enumerable: true,
229
+ get() {
230
+ return this[activityDefSymbol].triggeredByEvent;
231
+ },
232
+ });
233
+
234
+ Object.defineProperty(proto, 'attachedTo', {
235
+ enumerable: true,
236
+ get() {
237
+ const attachedToId = this[flagsSymbol].attachedTo;
238
+ if (!attachedToId) return null;
239
+ return this.getActivityById(attachedToId);
240
+ },
241
+ });
242
+
243
+ Object.defineProperty(proto, 'eventDefinitions', {
244
+ enumerable: true,
245
+ get() {
246
+ return this[eventDefinitionsSymbol];
247
+ },
248
+ });
249
+
250
+ proto.activate = function activate() {
251
+ if (this[flagsSymbol].isForCompensation) return;
252
+ return this._consumeInbound();
253
+ };
254
+
255
+ proto.deactivate = function deactivate() {
256
+ const broker = this.broker;
257
+ broker.cancel('_run-on-inbound');
258
+ broker.cancel('_format-consumer');
259
+ };
260
+
261
+ proto.init = function init(initContent) {
262
+ const id = this.id;
263
+ const exec = this[execSymbol];
264
+ const executionId = exec.initExecutionId = exec.initExecutionId || getUniqueId(id);
265
+ this.logger.debug(`<${id}> initialized with executionId <${executionId}>`);
266
+ this._publishEvent('init', this._createMessage({...initContent, executionId}));
267
+ };
268
+
269
+ proto.run = function run(runContent) {
270
+ const id = this.id;
271
+ if (this.isRunning) throw new Error(`activity <${id}> is already running`);
272
+
273
+ const exec = this[execSymbol];
274
+ const executionId = exec.executionId = exec.initExecutionId || getUniqueId(id);
275
+ exec.initExecutionId = null;
276
+
277
+ this._consumeApi();
278
+
279
+ const content = this._createMessage({...runContent, executionId});
280
+ const broker = this.broker;
281
+
282
+ broker.publish('run', 'run.enter', content);
283
+ broker.publish('run', 'run.start', cloneContent(content));
284
+
285
+ this._consumeRunQ();
286
+ };
287
+
288
+ proto.recover = function recover(state) {
289
+ if (this.isRunning) throw new Error(`cannot recover running activity <${this.id}>`);
290
+ if (!state) return;
291
+
292
+ this.stopped = state.stopped;
293
+ this.status = state.status;
294
+ const exec = this[execSymbol];
295
+ exec.executionId = state.executionId;
296
+
297
+ this[countersSymbol] = {...this[countersSymbol], ...state.counters};
298
+
299
+ if (state.execution) {
300
+ exec.execution = new ActivityExecution(this, this.context).recover(state.execution);
151
301
  }
152
302
 
153
- function run(runContent) {
154
- if (activityApi.isRunning) throw new Error(`activity <${id}> is already running`);
155
-
156
- executionId = initExecutionId || getUniqueId(id);
157
- initExecutionId = undefined;
158
-
159
- consumeApi();
160
-
161
- const content = createMessage({...runContent, executionId});
303
+ this.broker.recover(state.broker);
162
304
 
163
- broker.publish('run', 'run.enter', content);
164
- broker.publish('run', 'run.start', cloneContent(content));
305
+ return this;
306
+ };
165
307
 
166
- consumeRunQ();
308
+ proto.resume = function resume() {
309
+ if (this[consumingSymbol]) {
310
+ throw new Error(`cannot resume running activity <${this.id}>`);
167
311
  }
168
-
169
- function createMessage(override = {}) {
170
- const result = {
171
- ...override,
172
- id,
173
- type,
174
- ...(name ? {name} : undefined),
175
- ...(status ? {status} : undefined),
176
- parent: cloneParent(parent),
177
- };
178
-
179
- const flags = {isEnd, isStart, isSubProcess, isMultiInstance, isForCompensation, attachedTo, isTransaction};
180
- for (const flag in flags) {
181
- if (flags[flag]) result[flag] = flags[flag];
182
- }
183
-
184
- return result;
185
- }
186
-
187
- function recover(state) {
188
- if (activityApi.isRunning) throw new Error(`cannot recover running activity <${id}>`);
189
- if (!state) return;
190
-
191
- stopped = state.stopped;
192
- status = state.status;
193
- executionId = state.executionId;
194
-
195
- counters = {...counters, ...state.counters};
196
-
197
- if (state.execution) {
198
- execution = ActivityExecution(activityApi, context).recover(state.execution);
199
- }
200
-
201
- broker.recover(state.broker);
202
-
203
- return activityApi;
312
+ if (!this.status) return this.activate();
313
+
314
+ this.stopped = false;
315
+
316
+ this._consumeApi();
317
+
318
+ const content = this._createMessage();
319
+ this.broker.publish('run', 'run.resume', content, {persistent: false});
320
+ this._consumeRunQ();
321
+ };
322
+
323
+ proto.discard = function discard(discardContent) {
324
+ if (!this.status) return this._runDiscard(discardContent);
325
+ const execution = this[execSymbol].execution;
326
+ if (execution && !execution.completed) return execution.discard();
327
+
328
+ this._deactivateRunConsumers();
329
+ const broker = this.broker;
330
+ broker.getQueue('run-q').purge();
331
+ broker.publish('run', 'run.discard', cloneContent(this[stateMessageSymbol].content));
332
+ this._consumeRunQ();
333
+ };
334
+
335
+ proto.stop = function stop() {
336
+ if (!this[consumingSymbol]) return;
337
+ return this.getApi().stop();
338
+ };
339
+
340
+ proto.next = function next() {
341
+ if (!this.environment.settings.step) return;
342
+ const stateMessage = this[stateMessageSymbol];
343
+ if (!stateMessage) return;
344
+ if (this.status === 'executing') return false;
345
+ if (this.status === 'formatting') return false;
346
+ const current = stateMessage;
347
+ stateMessage.ack();
348
+ return current;
349
+ };
350
+
351
+ proto.shake = function shake() {
352
+ this._shakeOutbound({content: this._createMessage()});
353
+ };
354
+
355
+ proto.evaluateOutbound = function evaluateOutbound(fromMessage, discardRestAtTake, callback) {
356
+ return this[flowsSymbol].outboundEvaluator.evaluate(fromMessage, discardRestAtTake, callback);
357
+ };
358
+
359
+ proto.getState = function getState() {
360
+ const msg = this._createMessage();
361
+
362
+ const exec = this[execSymbol];
363
+ return {
364
+ ...msg,
365
+ executionId: exec.executionId,
366
+ stopped: this.stopped,
367
+ behaviour: {...this.behaviour},
368
+ counters: this.counters,
369
+ broker: this.broker.getState(true),
370
+ execution: exec.execution && exec.execution.getState(),
371
+ };
372
+ };
373
+
374
+ proto.getApi = function getApi(message) {
375
+ const execution = this[execSymbol].execution;
376
+ if (execution && !execution.completed) return execution.getApi(message);
377
+ return ActivityApi(this.broker, message || this[stateMessageSymbol]);
378
+ };
379
+
380
+ proto.getActivityById = function getActivityById(elementId) {
381
+ return this.context.getActivityById(elementId);
382
+ };
383
+
384
+ proto._runDiscard = function runDiscard(discardContent) {
385
+ const exec = this[execSymbol];
386
+ const executionId = exec.executionId = exec.initExecutionId || getUniqueId(this.id);
387
+ exec.initExecutionId = null;
388
+
389
+ this._consumeApi();
390
+
391
+ const content = this._createMessage({...discardContent, executionId});
392
+ this.broker.publish('run', 'run.discard', content);
393
+
394
+ this._consumeRunQ();
395
+ };
396
+
397
+ proto._discardRun = function discardRun() {
398
+ const status = this.status;
399
+ if (!status) return;
400
+
401
+ const execution = this[execSymbol].execution;
402
+ if (execution && !execution.completed) return;
403
+ switch (status) {
404
+ case 'executing':
405
+ case 'error':
406
+ case 'discarded':
407
+ return;
204
408
  }
205
409
 
206
- function resume() {
207
- if (consumingRunQ) {
208
- throw new Error(`cannot resume running activity <${id}>`);
209
- }
210
- if (!status) return activate();
410
+ this._deactivateRunConsumers();
411
+ if (this.extensions) this.extensions.deactivate();
412
+ const broker = this.broker;
413
+ broker.getQueue('run-q').purge();
414
+ broker.publish('run', 'run.discard', cloneContent(this[stateMessageSymbol].content));
415
+ this._consumeRunQ();
416
+ };
211
417
 
212
- stopped = false;
418
+ proto._shakeOutbound = function shakeOutbound(sourceMessage) {
419
+ const message = cloneMessage(sourceMessage);
420
+ message.content.sequence = message.content.sequence || [];
421
+ message.content.sequence.push({id: this.id, type: this.type});
213
422
 
214
- consumeApi();
423
+ const broker = this.broker;
424
+ this.broker.publish('api', 'activity.shake.start', message.content, {persistent: false, type: 'shake'});
215
425
 
216
- const content = createMessage({executionId});
217
- broker.publish('run', 'run.resume', content, {persistent: false});
218
- consumeRunQ();
426
+ if (this[flagsSymbol].isEnd) {
427
+ return broker.publish('event', 'activity.shake.end', message.content, {persistent: false, type: 'shake'});
219
428
  }
220
429
 
221
- function discard(discardContent) {
222
- if (!status) return runDiscard(discardContent);
223
- if (execution && !execution.completed) return execution.discard();
430
+ for (const flow of this[flowsSymbol].outboundSequenceFlows) flow.shake(message);
431
+ };
224
432
 
225
- deactivateRunConsumers();
226
- runQ.purge();
227
- broker.publish('run', 'run.discard', cloneContent(stateMessage.content));
228
- consumeRunQ();
433
+ proto._consumeInbound = function consumeInbound() {
434
+ if (this.status) return;
435
+ const inboundQ = this.broker.getQueue('inbound-q');
436
+ if (this[flagsSymbol].isParallelJoin) {
437
+ return inboundQ.consume(this[messageHandlersSymbol].onInbound, {consumerTag: '_run-on-inbound', prefetch: 1000});
229
438
  }
230
439
 
231
- function discardRun() {
232
- if (!status) return;
233
-
234
- if (execution && !execution.completed) return;
235
- switch (status) {
236
- case 'executing':
237
- case 'error':
238
- case 'discarded':
239
- return;
440
+ return inboundQ.consume(this[messageHandlersSymbol].onInbound, {consumerTag: '_run-on-inbound'});
441
+ };
442
+
443
+ proto._onInbound = function onInbound(routingKey, message) {
444
+ message.ack();
445
+ const id = this.id;
446
+ const broker = this.broker;
447
+ broker.cancel('_run-on-inbound');
448
+
449
+ const content = message.content;
450
+ const inbound = [cloneContent(content)];
451
+
452
+ switch (routingKey) {
453
+ case 'association.take':
454
+ case 'flow.take':
455
+ case 'activity.enter':
456
+ return this.run({
457
+ message: content.message,
458
+ inbound,
459
+ });
460
+ case 'flow.discard':
461
+ case 'activity.discard': {
462
+ let discardSequence;
463
+ if (content.discardSequence) discardSequence = content.discardSequence.slice();
464
+ return this._runDiscard({inbound, discardSequence});
240
465
  }
466
+ case 'association.complete': {
467
+ broker.cancel('_run-on-inbound');
241
468
 
242
- deactivateRunConsumers();
243
- if (extensions) extensions.deactivate();
244
- runQ.purge();
245
- broker.publish('run', 'run.discard', cloneContent(stateMessage.content));
246
- consumeRunQ();
247
- }
248
-
249
- function runDiscard(discardContent = {}) {
250
- executionId = initExecutionId || getUniqueId(id);
469
+ const compensationId = `${brokerSafeId(id)}_${brokerSafeId(content.sequenceId)}`;
470
+ this.logger.debug(`<${id}> completed compensation with id <${compensationId}>`);
251
471
 
252
- consumeApi();
253
-
254
- initExecutionId = undefined;
255
-
256
- const content = createMessage({...discardContent, executionId});
257
- broker.publish('run', 'run.discard', content);
258
-
259
- consumeRunQ();
260
- }
261
-
262
- function stop() {
263
- if (!consumingRunQ) return;
264
- return getApi().stop();
265
- }
266
-
267
- function onStop(message) {
268
- const running = consumingRunQ;
269
-
270
- stopped = true;
271
-
272
- consumingRunQ = false;
273
- broker.cancel('_activity-run');
274
- broker.cancel('_activity-api');
275
- broker.cancel('_activity-execution');
276
- broker.cancel('_run-on-inbound');
277
- broker.cancel('_format-consumer');
278
-
279
- if (running) {
280
- if (extensions) extensions.deactivate(message || createMessage());
281
- publishEvent('stop');
472
+ return this._publishEvent('compensation.end', this._createMessage({
473
+ executionId: compensationId,
474
+ }));
282
475
  }
283
476
  }
477
+ };
284
478
 
285
- function activate() {
286
- if (isForCompensation) return;
287
- return consumeInbound();
288
- }
479
+ proto._onJoinInbound = function onJoinInbound(routingKey, message) {
480
+ const {content} = message;
481
+ const {inboundSequenceFlows, inboundJoinFlows, inboundTriggers} = this[flowsSymbol];
482
+ const idx = inboundJoinFlows.findIndex((msg) => msg.content.id === content.id);
289
483
 
290
- function deactivate() {
291
- broker.cancel('_run-on-inbound');
292
- broker.cancel('_format-consumer');
293
- }
484
+ inboundJoinFlows.push(message);
294
485
 
295
- function consumeRunQ() {
296
- if (consumingRunQ) return;
486
+ if (idx > -1) return;
297
487
 
298
- consumingRunQ = true;
299
- runQ.assertConsumer(onRunMessage, {exclusive: true, consumerTag: '_activity-run'});
488
+ const allTouched = inboundJoinFlows.length >= inboundTriggers.length;
489
+ if (!allTouched) {
490
+ const remaining = inboundSequenceFlows.filter((inb, i, list) => list.indexOf(inb) === i).length - inboundJoinFlows.length;
491
+ return this.logger.debug(`<${this.id}> inbound ${message.content.action} from <${message.content.id}>, ${remaining} remaining`);
300
492
  }
301
493
 
302
- function consumeApi() {
303
- if (!executionId) return;
494
+ const evaluatedInbound = inboundJoinFlows.splice(0);
304
495
 
305
- broker.cancel('_activity-api');
306
- broker.subscribeTmp('api', `activity.*.${executionId}`, onApiMessage, {noAck: true, consumerTag: '_activity-api', priority: 100});
307
- }
496
+ let taken;
497
+ const inbound = evaluatedInbound.map((im) => {
498
+ if (im.fields.routingKey === 'flow.take') taken = true;
499
+ im.ack();
500
+ return cloneContent(im.content);
501
+ });
308
502
 
309
- function consumeInbound() {
310
- if (status) return;
311
- if (isParallelJoin) {
312
- return inboundQ.consume(onJoinInbound, {consumerTag: '_run-on-inbound', prefetch: 1000});
503
+ const discardSequence = !taken && evaluatedInbound.reduce((result, im) => {
504
+ if (!im.content.discardSequence) return result;
505
+ for (const sourceId of im.content.discardSequence) {
506
+ if (result.indexOf(sourceId) === -1) result.push(sourceId);
313
507
  }
508
+ return result;
509
+ }, []);
314
510
 
315
- return inboundQ.consume(onInbound, {consumerTag: '_run-on-inbound'});
316
- }
511
+ this.broker.cancel('_run-on-inbound');
317
512
 
318
- function deactivateRunConsumers() {
319
- broker.cancel('_activity-api');
320
- broker.cancel('_activity-run');
321
- broker.cancel('_activity-execution');
322
- consumingRunQ = false;
323
- }
513
+ if (!taken) return this._runDiscard({inbound, discardSequence});
514
+ return this.run({inbound});
515
+ };
324
516
 
325
- function onInboundEvent(routingKey, message) {
326
- const {fields, content, properties} = message;
517
+ proto._onInboundEvent = function onInboundEvent(routingKey, message) {
518
+ const {fields, content, properties} = message;
519
+ const id = this.id;
520
+ const inboundQ = this.broker.getQueue('inbound-q');
327
521
 
328
- switch (routingKey) {
329
- case 'activity.enter':
330
- case 'activity.discard': {
331
- if (content.id === attachedToActivity.id) {
332
- inboundQ.queueMessage(fields, cloneContent(content), properties);
333
- }
334
- break;
335
- }
336
- case 'flow.shake': {
337
- shakeOutbound(message);
338
- break;
339
- }
340
- case 'association.take':
341
- case 'flow.take':
342
- case 'flow.discard':
522
+ switch (routingKey) {
523
+ case 'activity.enter':
524
+ case 'activity.discard': {
525
+ if (content.id === this[flagsSymbol].attachedTo) {
343
526
  inboundQ.queueMessage(fields, cloneContent(content), properties);
344
- break;
345
- case 'association.discard': {
346
- logger.debug(`<${id}> compensation discarded`);
347
- inboundQ.purge();
348
- break;
349
527
  }
350
- case 'association.complete': {
351
- if (!isForCompensation) break;
528
+ break;
529
+ }
530
+ case 'flow.shake': {
531
+ return this._shakeOutbound(message);
532
+ }
533
+ case 'association.take':
534
+ case 'flow.take':
535
+ case 'flow.discard':
536
+ return inboundQ.queueMessage(fields, cloneContent(content), properties);
537
+ case 'association.discard': {
538
+ this.logger.debug(`<${id}> compensation discarded`);
539
+ return inboundQ.purge();
540
+ }
541
+ case 'association.complete': {
542
+ if (!this[flagsSymbol].isForCompensation) break;
352
543
 
353
- inboundQ.queueMessage(fields, cloneContent(content), properties);
544
+ inboundQ.queueMessage(fields, cloneContent(content), properties);
354
545
 
355
- const compensationId = `${brokerSafeId(id)}_${brokerSafeId(content.sequenceId)}`;
356
- publishEvent('compensation.start', createMessage({
357
- executionId: compensationId,
358
- placeholder: true,
359
- }));
546
+ const compensationId = `${brokerSafeId(id)}_${brokerSafeId(content.sequenceId)}`;
547
+ this._publishEvent('compensation.start', this._createMessage({
548
+ executionId: compensationId,
549
+ placeholder: true,
550
+ }));
360
551
 
361
- logger.debug(`<${id}> start compensation with id <${compensationId}>`);
552
+ this.logger.debug(`<${id}> start compensation with id <${compensationId}>`);
362
553
 
363
- consumeInbound();
364
- break;
365
- }
554
+ return this._consumeInbound();
366
555
  }
367
556
  }
368
-
369
- function onInbound(routingKey, message) {
370
- message.ack();
371
- broker.cancel('_run-on-inbound');
372
-
373
- const content = message.content;
374
- const inbound = [cloneContent(content)];
375
-
376
- switch (routingKey) {
377
- case 'association.take':
378
- case 'flow.take':
379
- case 'activity.enter':
380
- run({
381
- message: content.message,
382
- inbound,
383
- });
384
- break;
385
- case 'flow.discard':
386
- case 'activity.discard': {
387
- let discardSequence;
388
- if (content.discardSequence) discardSequence = content.discardSequence.slice();
389
- runDiscard({inbound, discardSequence});
390
- break;
391
- }
392
- case 'association.complete': {
393
- broker.cancel('_run-on-inbound');
394
-
395
- const compensationId = `${brokerSafeId(id)}_${brokerSafeId(content.sequenceId)}`;
396
- logger.debug(`<${id}> completed compensation with id <${compensationId}>`);
397
-
398
- publishEvent('compensation.end', createMessage({
399
- executionId: compensationId,
400
- }));
401
- break;
402
- }
557
+ };
558
+
559
+ proto._consumeRunQ = function consumeRunQ() {
560
+ if (this[consumingSymbol]) return;
561
+
562
+ this[consumingSymbol] = true;
563
+ this.broker.getQueue('run-q').assertConsumer(this[messageHandlersSymbol].onRunMessage, {exclusive: true, consumerTag: '_activity-run'});
564
+ };
565
+
566
+ proto._onRunMessage = function onRunMessage(routingKey, message, messageProperties) {
567
+ switch (routingKey) {
568
+ case 'run.outbound.discard':
569
+ case 'run.outbound.take':
570
+ case 'run.next':
571
+ return this._continueRunMessage(routingKey, message, messageProperties);
572
+ case 'run.resume': {
573
+ return this._onResumeMessage(message);
403
574
  }
404
575
  }
405
576
 
406
- function onJoinInbound(routingKey, message) {
407
- const {content} = message;
408
- const idx = inboundJoinFlows.findIndex((msg) => msg.content.id === content.id);
409
-
410
- inboundJoinFlows.push(message);
411
-
412
- if (idx > -1) return;
413
-
414
- const allTouched = inboundJoinFlows.length >= inboundTriggers.length;
415
- if (!allTouched) {
416
- const remaining = inboundSequenceFlows.filter((inb, i, list) => list.indexOf(inb) === i).length - inboundJoinFlows.length;
417
- return logger.debug(`<${id}> inbound ${message.content.action} from <${message.content.id}>, ${remaining} remaining`);
418
- }
577
+ const preStatus = this.status;
578
+ this.status = 'formatting';
579
+ return this.formatter.format(message, (err, formattedContent, formatted) => {
580
+ if (err) return this.emitFatal(err, message.content);
581
+ if (formatted) message.content = formattedContent;
582
+ this.status = preStatus;
583
+ this._continueRunMessage(routingKey, message, messageProperties);
584
+ });
585
+ };
419
586
 
420
- const evaluatedInbound = inboundJoinFlows.splice(0);
587
+ proto._continueRunMessage = function continueRunMessage(routingKey, message) {
588
+ const isRedelivered = message.fields.redelivered;
589
+ const content = cloneContent(message.content);
590
+ const correlationId = message.properties.correlationId;
421
591
 
422
- let taken;
423
- const inbound = evaluatedInbound.map((im) => {
424
- if (im.fields.routingKey === 'flow.take') taken = true;
425
- im.ack();
426
- return cloneContent(im.content);
427
- });
592
+ const id = this.id;
593
+ const step = this.environment.settings.step;
594
+ this[stateMessageSymbol] = message;
428
595
 
429
- const discardSequence = !taken && evaluatedInbound.reduce((result, im) => {
430
- if (!im.content.discardSequence) return result;
431
- im.content.discardSequence.forEach((sourceId) => {
432
- if (result.indexOf(sourceId) === -1) result.push(sourceId);
433
- });
434
- return result;
435
- }, []);
596
+ switch (routingKey) {
597
+ case 'run.enter': {
598
+ this.logger.debug(`<${id}> enter`, isRedelivered ? 'redelivered' : '');
436
599
 
437
- broker.cancel('_run-on-inbound');
600
+ this.status = 'entered';
601
+ if (!isRedelivered) {
602
+ this[execSymbol].execution = null;
603
+ }
438
604
 
439
- if (!taken) return runDiscard({inbound, discardSequence});
440
- return run({inbound});
441
- }
605
+ if (this.extensions) this.extensions.activate(cloneMessage(message), this);
606
+ if (this.bpmnIo) this.bpmnIo.activate(message);
442
607
 
443
- function onRunMessage(routingKey, message, messageProperties) {
444
- switch (routingKey) {
445
- case 'run.outbound.discard':
446
- case 'run.outbound.take':
447
- case 'run.next':
448
- return continueRunMessage(routingKey, message, messageProperties);
449
- case 'run.resume': {
450
- return onResumeMessage();
451
- }
608
+ if (!isRedelivered) this._publishEvent('enter', content, {correlationId});
609
+ break;
452
610
  }
611
+ case 'run.discard': {
612
+ this.logger.debug(`<${id}> discard`, isRedelivered ? 'redelivered' : '');
453
613
 
454
- const preStatus = status;
455
- status = 'formatting';
456
- return formatter(message, (err, formattedContent, formatted) => {
457
- if (err) return emitFatal(err, message.content);
458
- if (formatted) message.content = formattedContent;
459
- status = preStatus;
460
- continueRunMessage(routingKey, message, messageProperties);
461
- });
614
+ this.status = 'discard';
615
+ this[execSymbol].execution = null;
462
616
 
463
- function onResumeMessage() {
464
- message.ack();
617
+ if (this.extensions) this.extensions.activate(cloneMessage(message), this);
618
+ if (this.bpmnIo) this.bpmnIo.activate(message);
465
619
 
466
- const {fields} = stateMessage;
467
-
468
- switch (fields.routingKey) {
469
- case 'run.enter':
470
- case 'run.start':
471
- case 'run.discarded':
472
- case 'run.end':
473
- case 'run.leave':
474
- break;
475
- default:
476
- return;
620
+ if (!isRedelivered) {
621
+ this.broker.publish('run', 'run.discarded', content, {correlationId});
622
+ this._publishEvent('discard', content);
477
623
  }
478
-
479
- if (!fields.redelivered) return;
480
-
481
- logger.debug(`<${id}> resume from ${message.content.status}`);
482
-
483
- return broker.publish('run', fields.routingKey, cloneContent(stateMessage.content), stateMessage.properties);
624
+ break;
484
625
  }
485
- }
486
-
487
- function continueRunMessage(routingKey, message) {
488
- const {fields, content: originalContent, ack} = message;
489
- const isRedelivered = fields.redelivered;
490
- const content = cloneContent(originalContent);
491
- const {correlationId} = message.properties;
492
-
493
- stateMessage = message;
494
-
495
- switch (routingKey) {
496
- case 'run.enter': {
497
- logger.debug(`<${id}> enter`, isRedelivered ? 'redelivered' : '');
498
-
499
- status = 'entered';
500
- if (!isRedelivered) {
501
- execution = undefined;
502
- }
503
-
504
- if (extensions) extensions.activate(cloneMessage(message), activityApi);
505
- if (ioSpecification) ioSpecification.activate(message);
506
-
507
- if (!isRedelivered) publishEvent('enter', content, {correlationId});
508
- break;
626
+ case 'run.start': {
627
+ this.logger.debug(`<${id}> start`, isRedelivered ? 'redelivered' : '');
628
+ this.status = 'started';
629
+ if (!isRedelivered) {
630
+ this.broker.publish('run', 'run.execute', content, {correlationId});
631
+ this._publishEvent('start', content, {correlationId});
509
632
  }
510
- case 'run.discard': {
511
- logger.debug(`<${id}> discard`, isRedelivered ? 'redelivered' : '');
512
-
513
- status = 'discard';
514
- execution = undefined;
515
633
 
516
- if (extensions) extensions.activate(cloneMessage(message), activityApi);
517
- if (ioSpecification) ioSpecification.activate(message);
518
-
519
- if (!isRedelivered) {
520
- broker.publish('run', 'run.discarded', content, {correlationId});
521
- publishEvent('discard', content);
522
- }
523
- break;
524
- }
525
- case 'run.start': {
526
- logger.debug(`<${id}> start`, isRedelivered ? 'redelivered' : '');
527
- status = 'started';
528
- if (!isRedelivered) {
529
- broker.publish('run', 'run.execute', content, {correlationId});
530
- publishEvent('start', content, {correlationId});
531
- }
532
-
533
- break;
634
+ break;
635
+ }
636
+ case 'run.execute.passthrough': {
637
+ const execution = this.execution;
638
+ if (!isRedelivered && execution) {
639
+ this[executeMessageSymbol] = message;
640
+ return execution.passthrough(message);
534
641
  }
535
- case 'run.execute.passthrough': {
536
- if (!isRedelivered && execution) {
537
- executeMessage = message;
538
- return execution.passthrough(message);
539
- }
642
+ }
643
+ case 'run.execute': {
644
+ this.status = 'executing';
645
+ this[executeMessageSymbol] = message;
646
+
647
+ this.broker.getQueue('execution-q').assertConsumer(this[messageHandlersSymbol].onExecutionMessage, {exclusive: true, consumerTag: '_activity-execution'});
648
+ const exec = this[execSymbol];
649
+ if (!exec.execution) exec.execution = new ActivityExecution(this, this.context);
650
+
651
+ if (isRedelivered) {
652
+ return this._resumeExtensions(message, (err, formattedContent) => {
653
+ if (err) return this.emitFatal(err, message.content);
654
+ if (formattedContent) message.content = formattedContent;
655
+ this.status = 'executing';
656
+ return exec.execution.execute(message);
657
+ });
540
658
  }
541
- case 'run.execute': {
542
- status = 'executing';
543
- executeMessage = message;
544
659
 
545
- if (isRedelivered) {
546
- if (extensions) extensions.activate(cloneMessage(message), activityApi);
547
- if (ioSpecification) ioSpecification.activate(message);
548
- }
660
+ return exec.execution.execute(message);
661
+ }
662
+ case 'run.end': {
663
+ if (this.status === 'end') break;
549
664
 
550
- executionQ.assertConsumer(onExecutionMessage, {exclusive: true, consumerTag: '_activity-execution'});
551
- execution = execution || ActivityExecution(activityApi, context);
665
+ this[countersSymbol].taken++;
552
666
 
553
- return execution.execute(message);
554
- }
555
- case 'run.end': {
556
- if (status === 'end') break;
667
+ this.status = 'end';
557
668
 
558
- counters.taken++;
669
+ if (isRedelivered) break;
559
670
 
560
- status = 'end';
671
+ return this._doRunLeave(message, false, () => {
672
+ this._publishEvent('end', content, {correlationId});
673
+ if (!step) message.ack();
674
+ });
675
+ }
676
+ case 'run.error': {
677
+ this._publishEvent('error', {
678
+ ...content,
679
+ error: isRedelivered ? makeErrorFromMessage(message) : content.error,
680
+ }, {correlationId});
681
+ break;
682
+ }
683
+ case 'run.discarded': {
684
+ this.logger.debug(`<${content.executionId} (${id})> discarded`);
685
+ this[countersSymbol].discarded++;
561
686
 
562
- if (isRedelivered) break;
687
+ this.status = 'discarded';
688
+ content.outbound = undefined;
563
689
 
564
- return doRunLeave(false, () => {
565
- publishEvent('end', content, {correlationId});
566
- if (!step) ack();
690
+ if (!isRedelivered) {
691
+ return this._doRunLeave(message, true, () => {
692
+ if (!step) message.ack();
567
693
  });
568
694
  }
569
- case 'run.error': {
570
- publishEvent('error', cloneContent(content, {
571
- error: fields.redelivered ? makeErrorFromMessage(message) : content.error,
572
- }), {correlationId});
573
- break;
574
- }
575
- case 'run.discarded': {
576
- logger.debug(`<${executionId} (${id})> discarded`);
577
- counters.discarded++;
578
695
 
579
- status = 'discarded';
580
- content.outbound = undefined;
696
+ break;
697
+ }
698
+ case 'run.outbound.take': {
699
+ const flow = this._getOutboundSequenceFlowById(content.flow.id);
700
+ message.ack();
701
+ return flow.take(content.flow);
702
+ }
703
+ case 'run.outbound.discard': {
704
+ const flow = this._getOutboundSequenceFlowById(content.flow.id);
705
+ message.ack();
706
+ return flow.discard(content.flow);
707
+ }
708
+ case 'run.leave': {
709
+ this.status = undefined;
581
710
 
582
- if (!isRedelivered) {
583
- return doRunLeave(true, () => {
584
- if (!step) ack();
585
- });
586
- }
711
+ if (this.bpmnIo) this.bpmnIo.deactivate(message);
712
+ if (this.extensions) this.extensions.deactivate(message);
587
713
 
588
- break;
589
- }
590
- case 'run.outbound.take': {
591
- const flow = getOutboundSequenceFlowById(content.flow.id);
592
- ack();
593
- return flow.take(content.flow);
594
- }
595
- case 'run.outbound.discard': {
596
- const flow = getOutboundSequenceFlowById(content.flow.id);
597
- ack();
598
- return flow.discard(content.flow);
714
+ if (!isRedelivered) {
715
+ this.broker.publish('run', 'run.next', content, {persistent: false});
716
+ this._publishEvent('leave', content, {correlationId});
599
717
  }
600
- case 'run.leave': {
601
- status = undefined;
602
718
 
603
- if (extensions) extensions.deactivate(message);
604
-
605
- if (!isRedelivered) {
606
- broker.publish('run', 'run.next', cloneContent(content), {persistent: false});
607
- publishEvent('leave', content, {correlationId});
608
- }
609
-
610
- break;
611
- }
612
- case 'run.next':
613
- consumeInbound();
614
- break;
719
+ break;
615
720
  }
721
+ case 'run.next':
722
+ this._consumeInbound();
723
+ break;
724
+ }
616
725
 
617
- if (!step) ack();
726
+ if (!step) message.ack();
727
+ };
618
728
 
619
- function doRunLeave(isDiscarded, onOutbound) {
620
- if (content.ignoreOutbound) {
621
- broker.publish('run', 'run.leave', cloneContent(content), {correlationId});
622
- if (onOutbound) onOutbound();
623
- return;
624
- }
729
+ proto._onExecutionMessage = function onExecutionMessage(routingKey, message) {
730
+ const executeMessage = this[executeMessageSymbol];
731
+ const content = cloneContent({
732
+ ...executeMessage.content,
733
+ ...message.content,
734
+ executionId: executeMessage.content.executionId,
735
+ parent: {...this.parent},
736
+ });
625
737
 
626
- return doOutbound(cloneMessage(message), isDiscarded, (err, outbound) => {
627
- if (err) {
628
- return publishEvent('error', cloneContent(content, {error: err}), {correlationId});
629
- }
738
+ const {correlationId} = message.properties;
630
739
 
631
- broker.publish('run', 'run.leave', cloneContent(content, {
632
- ...(outbound.length ? {outbound} : undefined),
633
- }), {correlationId});
740
+ this._publishEvent(routingKey, content, message.properties);
741
+ const broker = this.broker;
634
742
 
635
- if (onOutbound) onOutbound();
743
+ switch (routingKey) {
744
+ case 'execution.outbound.take': {
745
+ return this._doOutbound(message, false, (err, outbound) => {
746
+ message.ack();
747
+ if (err) return this.emitFatal(err, content);
748
+ broker.publish('run', 'run.execute.passthrough', cloneContent(content, {outbound}));
749
+ return this._ackRunExecuteMessage();
636
750
  });
637
751
  }
752
+ case 'execution.error': {
753
+ this.status = 'error';
754
+ broker.publish('run', 'run.error', content, {correlationId});
755
+ broker.publish('run', 'run.discarded', content, {correlationId});
756
+ break;
757
+ }
758
+ case 'execution.discard':
759
+ this.status = 'discarded';
760
+ broker.publish('run', 'run.discarded', content, {correlationId});
761
+ break;
762
+ default: {
763
+ this.status = 'executed';
764
+ broker.publish('run', 'run.end', content, {correlationId});
765
+ }
638
766
  }
639
767
 
640
- function getOutboundSequenceFlowById(flowId) {
641
- return outboundSequenceFlows.find((flow) => flow.id === flowId);
768
+ message.ack();
769
+ this._ackRunExecuteMessage();
770
+ };
771
+
772
+ proto._ackRunExecuteMessage = function ackRunExecuteMessage() {
773
+ if (this.environment.settings.step) return;
774
+ const executeMessage = this[executeMessageSymbol];
775
+ this[executeMessageSymbol] = null;
776
+ executeMessage.ack();
777
+ };
778
+
779
+ proto._doRunLeave = function doRunLeave(message, isDiscarded, onOutbound) {
780
+ const {content, properties} = message;
781
+ const correlationId = properties.correlationId;
782
+ if (content.ignoreOutbound) {
783
+ this.broker.publish('run', 'run.leave', cloneContent(content), {correlationId});
784
+ return onOutbound();
642
785
  }
643
786
 
644
- function onExecutionMessage(routingKey, message) {
645
- const content = cloneContent({
646
- ...executeMessage.content,
647
- ...message.content,
648
- executionId: executeMessage.content.executionId,
649
- parent: {...parent},
650
- });
787
+ return this._doOutbound(cloneMessage(message), isDiscarded, (err, outbound) => {
788
+ if (err) {
789
+ return this._publishEvent('error', {...content, error: err}, {correlationId});
790
+ }
651
791
 
652
- const {correlationId} = message.properties;
792
+ this.broker.publish('run', 'run.leave', cloneContent(content, {
793
+ ...(outbound.length ? {outbound} : undefined),
794
+ }), {correlationId});
653
795
 
654
- publishEvent(routingKey, content, message.properties);
796
+ onOutbound();
797
+ });
798
+ };
655
799
 
656
- switch (routingKey) {
657
- case 'execution.outbound.take': {
658
- return doOutbound(cloneMessage(message), false, (err, outbound) => {
659
- message.ack();
660
- if (err) return emitFatal(err, content);
661
- broker.publish('run', 'run.execute.passthrough', cloneContent(content, {outbound}));
662
- return ackRunExecuteMessage();
663
- });
664
- }
665
- case 'execution.error': {
666
- status = 'error';
667
- broker.publish('run', 'run.error', content, {correlationId});
668
- broker.publish('run', 'run.discarded', content, {correlationId});
669
- break;
670
- }
671
- case 'execution.discard':
672
- status = 'discarded';
673
- broker.publish('run', 'run.discarded', content, {correlationId});
674
- break;
675
- default: {
676
- status = 'executed';
677
- broker.publish('run', 'run.end', content, {correlationId});
678
- }
679
- }
800
+ proto._doOutbound = function doOutbound(fromMessage, isDiscarded, callback) {
801
+ const outboundSequenceFlows = this[flowsSymbol].outboundSequenceFlows;
802
+ if (!outboundSequenceFlows.length) return callback(null, []);
680
803
 
681
- message.ack();
682
- ackRunExecuteMessage();
804
+ const fromContent = fromMessage.content;
683
805
 
684
- function ackRunExecuteMessage() {
685
- if (step) return;
686
- if (!executeMessage) return;
806
+ let discardSequence = fromContent.discardSequence;
807
+ if (isDiscarded && !discardSequence && this[flagsSymbol].attachedTo && fromContent.inbound && fromContent.inbound[0]) {
808
+ discardSequence = [fromContent.inbound[0].id];
809
+ }
687
810
 
688
- const ackMessage = executeMessage;
689
- executeMessage = null;
690
- ackMessage.ack();
691
- }
811
+ let outboundFlows;
812
+ if (isDiscarded) {
813
+ outboundFlows = outboundSequenceFlows.map((flow) => formatFlowAction(flow, {action: 'discard'}));
814
+ } else if (fromContent.outbound && fromContent.outbound.length) {
815
+ outboundFlows = outboundSequenceFlows.map((flow) => formatFlowAction(flow, fromContent.outbound.filter((f) => f.id === flow.id).pop()));
692
816
  }
693
817
 
694
- function onApiMessage(routingKey, message) {
695
- const messageType = message.properties.type;
696
- switch (messageType) {
697
- case 'discard': {
698
- discardRun(message);
699
- break;
700
- }
701
- case 'stop': {
702
- onStop(message);
703
- break;
704
- }
705
- case 'shake': {
706
- shakeOutbound(message);
707
- break;
708
- }
709
- }
818
+ if (outboundFlows) {
819
+ this._doRunOutbound(outboundFlows, fromContent, discardSequence);
820
+ return callback(null, outboundFlows);
710
821
  }
711
822
 
712
- function shake() {
713
- shakeOutbound({content: createMessage()});
823
+ return this.evaluateOutbound(fromMessage, fromContent.outboundTakeOne, (err, evaluatedOutbound) => {
824
+ if (err) return callback(new ActivityError(err.message, fromMessage, err));
825
+ const outbound = this._doRunOutbound(evaluatedOutbound, fromContent, discardSequence);
826
+ return callback(null, outbound);
827
+ });
828
+ };
829
+
830
+ proto._doRunOutbound = function doRunOutbound(outboundList, content, discardSequence) {
831
+ for (const outboundFlow of outboundList) {
832
+ const {id: flowId, action} = outboundFlow;
833
+ this.broker.publish('run', 'run.outbound.' + action, cloneContent(content, {
834
+ flow: {
835
+ ...outboundFlow,
836
+ sequenceId: getUniqueId(`${flowId}_${action}`),
837
+ ...(discardSequence ? {discardSequence: discardSequence.slice()} : undefined),
838
+ },
839
+ }));
840
+ }
841
+ return outboundList;
842
+ };
843
+
844
+ proto._onResumeMessage = function onResumeMessage(message) {
845
+ message.ack();
846
+
847
+ const stateMessage = this[stateMessageSymbol];
848
+ const {fields} = stateMessage;
849
+
850
+ switch (fields.routingKey) {
851
+ case 'run.enter':
852
+ case 'run.start':
853
+ case 'run.discarded':
854
+ case 'run.end':
855
+ case 'run.leave':
856
+ break;
857
+ default:
858
+ return;
714
859
  }
715
860
 
716
- function shakeOutbound(sourceMessage) {
717
- const message = cloneMessage(sourceMessage);
718
- message.content.sequence = message.content.sequence || [];
719
- message.content.sequence.push({id, type});
861
+ if (!fields.redelivered) return;
720
862
 
721
- broker.publish('api', 'activity.shake.start', message.content, {persistent: false, type: 'shake'});
863
+ this.logger.debug(`<${this.id}> resume from ${message.content.status}`);
722
864
 
723
- if (isEnd) {
724
- return broker.publish('event', 'activity.shake.end', message.content, {persistent: false, type: 'shake'});
725
- }
865
+ return this.broker.publish('run', fields.routingKey, cloneContent(stateMessage.content), stateMessage.properties);
866
+ };
726
867
 
727
- outboundSequenceFlows.forEach((f) => f.shake(message));
728
- }
868
+ proto._publishEvent = function publishEvent(state, content, properties = {}) {
869
+ this.broker.publish('event', `activity.${state}`, cloneContent(content, {state}), {
870
+ ...properties,
871
+ type: state,
872
+ mandatory: state === 'error',
873
+ persistent: 'persistent' in properties ? properties.persistent : state !== 'stop',
874
+ });
875
+ };
729
876
 
730
- function publishEvent(state, content, messageProperties = {}) {
731
- if (!state) return;
732
- if (!content) content = createMessage();
733
- broker.publish('event', `activity.${state}`, {...content, state}, {
734
- ...messageProperties,
735
- type: state,
736
- mandatory: state === 'error',
737
- persistent: 'persistent' in messageProperties ? messageProperties.persistent : state !== 'stop',
738
- });
739
- }
877
+ proto._onStop = function onStop(message) {
878
+ const running = this[consumingSymbol];
740
879
 
741
- function doOutbound(fromMessage, isDiscarded, callback) {
742
- if (!outboundSequenceFlows.length) return callback(null, []);
880
+ this.stopped = true;
743
881
 
744
- const fromContent = fromMessage.content;
882
+ this[consumingSymbol] = false;
883
+ const broker = this.broker;
884
+ broker.cancel('_activity-run');
885
+ broker.cancel('_activity-api');
886
+ broker.cancel('_activity-execution');
887
+ broker.cancel('_run-on-inbound');
888
+ broker.cancel('_format-consumer');
745
889
 
746
- let discardSequence = fromContent.discardSequence;
747
- if (isDiscarded && !discardSequence && attachedTo && fromContent.inbound && fromContent.inbound[0]) {
748
- discardSequence = [fromContent.inbound[0].id];
890
+ if (running) {
891
+ if (this.extensions) this.extensions.deactivate(message || this._createMessage());
892
+ this._publishEvent('stop', this._createMessage());
893
+ }
894
+ };
895
+
896
+ proto._consumeApi = function consumeApi() {
897
+ const executionId = this[execSymbol].executionId;
898
+ if (!executionId) return;
899
+ const broker = this.broker;
900
+ broker.cancel('_activity-api');
901
+ broker.subscribeTmp('api', `activity.*.${executionId}`, this[messageHandlersSymbol].onApiMessage, {noAck: true, consumerTag: '_activity-api', priority: 100});
902
+ };
903
+
904
+ proto._onApiMessage = function onApiMessage(routingKey, message) {
905
+ switch (message.properties.type) {
906
+ case 'discard': {
907
+ return this._discardRun(message);
749
908
  }
750
-
751
- let outboundFlows;
752
- if (isDiscarded) {
753
- outboundFlows = outboundSequenceFlows.map((flow) => formatFlowAction(flow, {action: 'discard'}));
754
- } else if (fromContent.outbound && fromContent.outbound.length) {
755
- outboundFlows = outboundSequenceFlows.map((flow) => formatFlowAction(flow, fromContent.outbound.filter((f) => f.id === flow.id).pop()));
909
+ case 'stop': {
910
+ return this._onStop(message);
756
911
  }
757
-
758
- if (outboundFlows) {
759
- doRunOutbound(outboundFlows);
760
- return callback(null, outboundFlows);
912
+ case 'shake': {
913
+ return this._shakeOutbound(message);
761
914
  }
915
+ }
916
+ };
917
+
918
+ proto._createMessage = function createMessage(override) {
919
+ const name = this.name, status = this.status, parent = this.parent;
920
+ const result = {
921
+ ...override,
922
+ id: this.id,
923
+ type: this.type,
924
+ ...(name ? {name} : undefined),
925
+ ...(status ? {status} : undefined),
926
+ ...(parent ? {parent: cloneParent(parent)} : undefined),
927
+ };
762
928
 
763
- return evaluateOutbound(fromMessage, fromContent.outboundTakeOne, (err, evaluatedOutbound) => {
764
- if (err) return callback(new ActivityError(err.message, fromMessage, err));
929
+ for (const [flag, value] of Object.entries(this[flagsSymbol])) {
930
+ if (value) result[flag] = value;
931
+ }
765
932
 
766
- const outbound = doRunOutbound(evaluatedOutbound);
767
- return callback(null, outbound);
768
- });
933
+ return result;
934
+ };
769
935
 
770
- function doRunOutbound(outboundList) {
771
- return outboundList.map((outboundFlow) => {
772
- const {id: flowId, action} = outboundFlow;
773
- broker.publish('run', 'run.outbound.' + action, cloneContent(fromContent, {
774
- flow: {
775
- ...outboundFlow,
776
- sequenceId: getUniqueId(`${flowId}_${action}`),
777
- ...(discardSequence ? {discardSequence: discardSequence.slice()} : undefined),
778
- },
779
- }));
780
-
781
- return outboundFlow;
782
- });
783
- }
784
- }
936
+ proto._getOutboundSequenceFlowById = function getOutboundSequenceFlowById(flowId) {
937
+ return this[flowsSymbol].outboundSequenceFlows.find((flow) => flow.id === flowId);
938
+ };
785
939
 
786
- function formatFlowAction(flow, options) {
787
- if (!options) options = {action: 'discard'};
940
+ proto._resumeExtensions = function resumeExtensions(message, callback) {
941
+ const extensions = this.extensions, bpmnIo = this.bpmnIo;
942
+ if (!extensions && !bpmnIo) return callback();
788
943
 
789
- const action = options.action;
790
- const message = options.message;
944
+ if (extensions) extensions.activate(cloneMessage(message), this);
945
+ if (bpmnIo) bpmnIo.activate(cloneMessage(message), this);
791
946
 
792
- return {
793
- ...options,
794
- id: flow.id,
795
- action,
796
- ...(flow.isDefault ? {isDefault: true} : undefined),
797
- ...(message !== undefined ? {message} : undefined),
798
- };
947
+ this.status = 'formatting';
948
+ return this.formatter.format(message, (err, formattedContent, formatted) => {
949
+ if (err) return callback(err);
950
+ return callback(null, formatted && formattedContent);
951
+ });
952
+ };
953
+
954
+ proto._deactivateRunConsumers = function _deactivateRunConsumers() {
955
+ const broker = this.broker;
956
+ broker.cancel('_activity-api');
957
+ broker.cancel('_activity-run');
958
+ broker.cancel('_activity-execution');
959
+ this[consumingSymbol] = false;
960
+ };
961
+
962
+ function OutboundEvaluator(activity, outboundFlows) {
963
+ this.activity = activity;
964
+ this.broker = activity.broker;
965
+ const flows = this.outboundFlows = outboundFlows.slice();
966
+ const defaultFlowIdx = flows.findIndex(({isDefault}) => isDefault);
967
+ if (defaultFlowIdx > -1) {
968
+ const [defaultFlow] = flows.splice(defaultFlowIdx, 1);
969
+ flows.push(defaultFlow);
799
970
  }
800
971
 
801
- function evaluateOutbound(fromMessage, discardRestAtTake, callback) {
802
- let conditionMet;
803
- const outbound = {};
804
-
805
- if (!outboundSequenceFlows.length) return completed();
972
+ this.defaultFlowIdx = outboundFlows.findIndex(({isDefault}) => isDefault);
973
+ this._onEvaluated = this.onEvaluated.bind(this);
974
+ this.evaluateArgs = {};
975
+ }
806
976
 
807
- const content = fromMessage.content;
808
- const message = content.message;
809
- const evaluateFlows = outboundSequenceFlows.slice();
810
- const defaultFlowIdx = outboundSequenceFlows.findIndex(({isDefault}) => isDefault);
811
- if (defaultFlowIdx > -1) {
812
- evaluateFlows.splice(defaultFlowIdx, 1);
813
- evaluateFlows.push(outboundSequenceFlows[defaultFlowIdx]);
814
- }
815
- let takenCount = 0;
977
+ OutboundEvaluator.prototype.evaluate = function evaluate(fromMessage, discardRestAtTake, callback) {
978
+ const outboundFlows = this.outboundFlows;
979
+
980
+ const args = this.evaluateArgs = {
981
+ fromMessage,
982
+ evaluationId: fromMessage.content.executionId,
983
+ discardRestAtTake,
984
+ callback,
985
+ conditionMet: false,
986
+ result: {},
987
+ takenCount: 0,
988
+ };
816
989
 
817
- broker.subscribeTmp('execution', 'evaluate.flow.#', (routingKey, {content: evalContent, ack}) => {
818
- const {id: flowId, action} = evalContent;
990
+ if (!outboundFlows.length) return this.completed();
819
991
 
820
- if (action === 'take') {
821
- takenCount++;
822
- conditionMet = true;
823
- }
992
+ const flows = args.flows = outboundFlows.slice();
824
993
 
825
- outbound[flowId] = evalContent;
994
+ this.broker.subscribeTmp('execution', 'evaluate.flow.#', this._onEvaluated, {
995
+ consumerTag: `_flow-evaluation-${args.evaluationId}`,
996
+ });
826
997
 
827
- if ('result' in evalContent) {
828
- logger.debug(`<${content.executionId} (${id})> flow <${flowId}> evaluated to: ${evalContent.result}`);
829
- }
998
+ return this.evaluateFlow(flows.shift());
999
+ };
830
1000
 
831
- let nextFlow = evaluateFlows.shift();
832
- if (!nextFlow) return completed();
1001
+ OutboundEvaluator.prototype.onEvaluated = function onEvaluated(routingKey, message) {
1002
+ const content = message.content;
1003
+ const {id: flowId, action, evaluationId} = message.content;
1004
+ const args = this.evaluateArgs;
833
1005
 
834
- if (discardRestAtTake && conditionMet) {
835
- do {
836
- outbound[nextFlow.id] = formatFlowAction(nextFlow, {action: 'discard'});
837
- } while ((nextFlow = evaluateFlows.shift()));
838
- return completed();
839
- }
1006
+ if (action === 'take') {
1007
+ args.takenCount++;
1008
+ args.conditionMet = true;
1009
+ }
840
1010
 
841
- if (conditionMet && nextFlow.isDefault) {
842
- outbound[nextFlow.id] = formatFlowAction(nextFlow, {action: 'discard'});
843
- return completed();
844
- }
1011
+ args.result[flowId] = content;
845
1012
 
846
- ack();
847
- evaluateSequenceFlows(nextFlow);
848
- }, {consumerTag: `_flow-evaluation-${executionId}`});
1013
+ if ('result' in content) {
1014
+ this.activity.logger.debug(`<${evaluationId} (${this.activity.id})> flow <${flowId}> evaluated to: ${!!content.result}`);
1015
+ }
849
1016
 
850
- return evaluateSequenceFlows(evaluateFlows.shift());
1017
+ let nextFlow = args.flows.shift();
1018
+ if (!nextFlow) return this.completed();
851
1019
 
852
- function completed(err) {
853
- broker.cancel(`_flow-evaluation-${executionId}`);
854
- if (err) return callback(err);
1020
+ if (args.discardRestAtTake && args.conditionMet) {
1021
+ do {
1022
+ args.result[nextFlow.id] = formatFlowAction(nextFlow, {action: 'discard'});
1023
+ } while ((nextFlow = args.flows.shift()));
1024
+ return this.completed();
1025
+ }
855
1026
 
856
- if (!takenCount) {
857
- const nonTakenError = new ActivityError(`<${id}> no conditional flow taken`, fromMessage);
858
- logger.error(`<${id}>`, nonTakenError);
859
- return callback(nonTakenError);
860
- }
1027
+ if (args.conditionMet && nextFlow.isDefault) {
1028
+ args.result[nextFlow.id] = formatFlowAction(nextFlow, {action: 'discard'});
1029
+ return this.completed();
1030
+ }
861
1031
 
862
- const outboundList = Object.keys(outbound).reduce((result, flowId) => {
863
- const flow = outbound[flowId];
864
- result.push({
865
- ...flow,
866
- ...(message !== undefined ? {message} : undefined),
867
- });
868
- return result;
869
- }, []);
1032
+ message.ack();
1033
+ this.evaluateFlow(nextFlow);
1034
+ };
870
1035
 
871
- return callback(null, outboundList);
872
- }
1036
+ OutboundEvaluator.prototype.evaluateFlow = function evaluateFlow(flow) {
1037
+ const broker = this.broker;
1038
+ if (flow.isDefault) {
1039
+ return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {action: 'take'}), {persistent: false});
1040
+ }
873
1041
 
874
- function evaluateSequenceFlows(flow) {
875
- if (!flow) return completed();
1042
+ const flowCondition = flow.getCondition();
1043
+ if (!flowCondition) {
1044
+ return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {action: 'take'}), {persistent: false});
1045
+ }
876
1046
 
877
- if (flow.isDefault) {
878
- return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {action: 'take'}), {persistent: false});
879
- }
1047
+ const {fromMessage, evaluationId} = this.evaluateArgs;
1048
+ flowCondition.execute(cloneMessage(fromMessage), (err, result) => {
1049
+ if (err) return this.completed(err);
1050
+ const action = result ? 'take' : 'discard';
1051
+ return broker.publish('execution', 'evaluate.flow.' + action, formatFlowAction(flow, {
1052
+ action,
1053
+ result,
1054
+ evaluationId,
1055
+ }), {persistent: false});
1056
+ });
1057
+ };
880
1058
 
881
- const flowCondition = flow.getCondition();
882
- if (!flowCondition) {
883
- return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {action: 'take'}), {persistent: false});
884
- }
1059
+ OutboundEvaluator.prototype.completed = function completed(err) {
1060
+ const {callback, evaluationId, fromMessage, result, takenCount} = this.evaluateArgs;
1061
+ this.broker.cancel(`_flow-evaluation-${evaluationId}`);
885
1062
 
886
- flowCondition.execute(cloneMessage(fromMessage), (err, result) => {
887
- if (err) return completed(err);
888
- const action = result ? 'take' : 'discard';
889
- return broker.publish('execution', 'evaluate.flow.' + action, formatFlowAction(flow, {
890
- action,
891
- result,
892
- }), {persistent: false});
893
- });
894
- }
895
- }
1063
+ if (err) return callback(err);
896
1064
 
897
- function getActivityById(elementId) {
898
- return context.getActivityById(elementId);
1065
+ if (!takenCount && this.outboundFlows.length) {
1066
+ const nonTakenError = new ActivityError(`<${this.activity.id}> no conditional flow taken`, fromMessage);
1067
+ return callback(nonTakenError);
899
1068
  }
900
1069
 
901
- function getState() {
902
- const msg = createMessage();
903
-
904
- return {
905
- ...msg,
906
- status,
907
- executionId,
908
- stopped,
909
- behaviour: {...behaviour},
910
- counters: {...counters},
911
- broker: broker.getState(),
912
- execution: execution && execution.getState(),
913
- };
1070
+ const message = fromMessage.content.message;
1071
+ const evaluationResult = [];
1072
+ for (const flow of Object.values(result)) {
1073
+ evaluationResult.push({
1074
+ ...flow,
1075
+ ...(message !== undefined ? {message} : undefined),
1076
+ });
914
1077
  }
915
1078
 
916
- function next() {
917
- if (!step) return;
918
- if (!stateMessage) return;
919
- if (status === 'executing') return false;
920
- if (status === 'formatting') return false;
921
- const current = stateMessage;
922
- stateMessage.ack();
923
- return current;
924
- }
1079
+ return callback(null, evaluationResult);
1080
+ };
925
1081
 
926
- function getApi(message) {
927
- if (execution && !execution.completed) return execution.getApi(message);
928
- return ActivityApi(broker, message || stateMessage);
929
- }
1082
+ function formatFlowAction(flow, options) {
1083
+ return {
1084
+ ...options,
1085
+ id: flow.id,
1086
+ action: options.action,
1087
+ ...(flow.isDefault ? {isDefault: true} : undefined),
1088
+ };
930
1089
  }