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