bpmn-elements 6.0.1 → 8.0.1

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 +341 -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 +1105 -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 +16 -16
  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 +914 -776
  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,1081 @@ 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
-
514
- status = 'discard';
515
- execution = undefined;
516
659
 
517
- if (extensions) extensions.activate(cloneMessage(message), activityApi);
518
- if (bpmnIo) bpmnIo.activate(message);
660
+ return exec.execution.execute(message);
661
+ }
662
+ case 'run.end': {
663
+ if (this.status === 'end') break;
519
664
 
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;
665
+ this[kCounters].taken++;
562
666
 
563
- counters.taken++;
667
+ this.status = 'end';
564
668
 
565
- status = 'end';
669
+ return this._doRunLeave(message, false, () => {
670
+ this._publishEvent('end', content, {correlationId});
671
+ if (!step) message.ack();
672
+ });
673
+ }
674
+ case 'run.error': {
675
+ this._publishEvent('error', {
676
+ ...content,
677
+ error: isRedelivered ? makeErrorFromMessage(message) : content.error,
678
+ }, {correlationId});
679
+ break;
680
+ }
681
+ case 'run.discarded': {
682
+ this.logger.debug(`<${content.executionId} (${id})> discarded`);
683
+ this[kCounters].discarded++;
566
684
 
567
- if (isRedelivered) break;
685
+ this.status = 'discarded';
686
+ content.outbound = undefined;
568
687
 
569
- return doRunLeave(false, () => {
570
- publishEvent('end', content, {correlationId});
571
- if (!step) ack();
688
+ if (!isRedelivered) {
689
+ return this._doRunLeave(message, true, () => {
690
+ if (!step) message.ack();
572
691
  });
573
692
  }
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
693
 
584
- status = 'discarded';
585
- content.outbound = undefined;
694
+ break;
695
+ }
696
+ case 'run.outbound.take': {
697
+ const flow = this._getOutboundSequenceFlowById(content.flow.id);
698
+ message.ack();
699
+ return flow.take(content.flow);
700
+ }
701
+ case 'run.outbound.discard': {
702
+ const flow = this._getOutboundSequenceFlowById(content.flow.id);
703
+ message.ack();
704
+ return flow.discard(content.flow);
705
+ }
706
+ case 'run.leave': {
707
+ this.status = undefined;
586
708
 
587
- if (!isRedelivered) {
588
- return doRunLeave(true, () => {
589
- if (!step) ack();
590
- });
591
- }
709
+ if (this.bpmnIo) this.bpmnIo.deactivate(message);
710
+ if (this.extensions) this.extensions.deactivate(message);
592
711
 
593
- break;
594
- }
595
- case 'run.outbound.take': {
596
- const flow = getOutboundSequenceFlowById(content.flow.id);
597
- ack();
598
- return flow.take(content.flow);
712
+ if (!isRedelivered) {
713
+ this.broker.publish('run', 'run.next', content, {persistent: false});
714
+ this._publishEvent('leave', content, {correlationId});
599
715
  }
600
- case 'run.outbound.discard': {
601
- const flow = getOutboundSequenceFlowById(content.flow.id);
602
- ack();
603
- return flow.discard(content.flow);
604
- }
605
- case 'run.leave': {
606
- status = undefined;
607
-
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
716
 
616
- break;
617
- }
618
- case 'run.next':
619
- consumeInbound();
620
- break;
717
+ break;
621
718
  }
719
+ case 'run.next':
720
+ this._consumeInbound();
721
+ break;
722
+ }
622
723
 
623
- if (!step) ack();
724
+ if (!step) message.ack();
725
+ };
624
726
 
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
- }
727
+ proto._onExecutionMessage = function onExecutionMessage(routingKey, message) {
728
+ const executeMessage = this[kExecuteMessage];
729
+ const content = cloneContent({
730
+ ...executeMessage.content,
731
+ ...message.content,
732
+ executionId: executeMessage.content.executionId,
733
+ parent: {...this.parent},
734
+ });
631
735
 
632
- return doOutbound(cloneMessage(message), isDiscarded, (err, outbound) => {
633
- if (err) {
634
- return publishEvent('error', cloneContent(content, {error: err}), {correlationId});
635
- }
736
+ const {correlationId} = message.properties;
636
737
 
637
- broker.publish('run', 'run.leave', cloneContent(content, {
638
- ...(outbound.length ? {outbound} : undefined),
639
- }), {correlationId});
738
+ this._publishEvent(routingKey, content, message.properties);
739
+ const broker = this.broker;
640
740
 
641
- if (onOutbound) onOutbound();
741
+ switch (routingKey) {
742
+ case 'execution.outbound.take': {
743
+ return this._doOutbound(message, false, (err, outbound) => {
744
+ message.ack();
745
+ if (err) return this.emitFatal(err, content);
746
+ broker.publish('run', 'run.execute.passthrough', cloneContent(content, {outbound}));
747
+ return this._ackRunExecuteMessage();
642
748
  });
643
749
  }
750
+ case 'execution.error': {
751
+ this.status = 'error';
752
+ broker.publish('run', 'run.error', content, {correlationId});
753
+ broker.publish('run', 'run.discarded', content, {correlationId});
754
+ break;
755
+ }
756
+ case 'execution.discard':
757
+ this.status = 'discarded';
758
+ broker.publish('run', 'run.discarded', content, {correlationId});
759
+ break;
760
+ default: {
761
+ this.status = 'executed';
762
+ broker.publish('run', 'run.end', content, {correlationId});
763
+ }
644
764
  }
645
765
 
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
- });
657
- }
658
-
659
- function getOutboundSequenceFlowById(flowId) {
660
- return outboundSequenceFlows.find((flow) => flow.id === flowId);
766
+ message.ack();
767
+ this._ackRunExecuteMessage();
768
+ };
769
+
770
+ proto._ackRunExecuteMessage = function ackRunExecuteMessage() {
771
+ if (this.environment.settings.step) return;
772
+ const executeMessage = this[kExecuteMessage];
773
+ this[kExecuteMessage] = null;
774
+ executeMessage.ack();
775
+ };
776
+
777
+ proto._doRunLeave = function doRunLeave(message, isDiscarded, onOutbound) {
778
+ const {content, properties} = message;
779
+ const correlationId = properties.correlationId;
780
+ if (content.ignoreOutbound) {
781
+ this.broker.publish('run', 'run.leave', cloneContent(content), {correlationId});
782
+ return onOutbound();
661
783
  }
662
784
 
663
- function onExecutionMessage(routingKey, message) {
664
- const content = cloneContent({
665
- ...executeMessage.content,
666
- ...message.content,
667
- executionId: executeMessage.content.executionId,
668
- parent: {...parent},
669
- });
785
+ return this._doOutbound(cloneMessage(message), isDiscarded, (err, outbound) => {
786
+ if (err) {
787
+ return this._publishEvent('error', {...content, error: err}, {correlationId});
788
+ }
670
789
 
671
- const {correlationId} = message.properties;
790
+ this.broker.publish('run', 'run.leave', cloneContent(content, {
791
+ ...(outbound.length ? {outbound} : undefined),
792
+ }), {correlationId});
672
793
 
673
- publishEvent(routingKey, content, message.properties);
794
+ onOutbound();
795
+ });
796
+ };
674
797
 
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
- }
798
+ proto._doOutbound = function doOutbound(fromMessage, isDiscarded, callback) {
799
+ const outboundSequenceFlows = this[kFlows].outboundSequenceFlows;
800
+ if (!outboundSequenceFlows.length) return callback(null, []);
699
801
 
700
- message.ack();
701
- ackRunExecuteMessage();
802
+ const fromContent = fromMessage.content;
702
803
 
703
- function ackRunExecuteMessage() {
704
- if (step) return;
705
- if (!executeMessage) return;
804
+ let discardSequence = fromContent.discardSequence;
805
+ if (isDiscarded && !discardSequence && this[kFlags].attachedTo && fromContent.inbound && fromContent.inbound[0]) {
806
+ discardSequence = [fromContent.inbound[0].id];
807
+ }
706
808
 
707
- const ackMessage = executeMessage;
708
- executeMessage = null;
709
- ackMessage.ack();
710
- }
809
+ let outboundFlows;
810
+ if (isDiscarded) {
811
+ outboundFlows = outboundSequenceFlows.map((flow) => formatFlowAction(flow, {action: 'discard'}));
812
+ } else if (fromContent.outbound && fromContent.outbound.length) {
813
+ outboundFlows = outboundSequenceFlows.map((flow) => formatFlowAction(flow, fromContent.outbound.filter((f) => f.id === flow.id).pop()));
711
814
  }
712
815
 
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
- }
816
+ if (outboundFlows) {
817
+ this._doRunOutbound(outboundFlows, fromContent, discardSequence);
818
+ return callback(null, outboundFlows);
729
819
  }
730
820
 
731
- function shake() {
732
- shakeOutbound({content: createMessage()});
821
+ return this.evaluateOutbound(fromMessage, fromContent.outboundTakeOne, (err, evaluatedOutbound) => {
822
+ if (err) return callback(new ActivityError(err.message, fromMessage, err));
823
+ const outbound = this._doRunOutbound(evaluatedOutbound, fromContent, discardSequence);
824
+ return callback(null, outbound);
825
+ });
826
+ };
827
+
828
+ proto._doRunOutbound = function doRunOutbound(outboundList, content, discardSequence) {
829
+ for (const outboundFlow of outboundList) {
830
+ const {id: flowId, action} = outboundFlow;
831
+ this.broker.publish('run', 'run.outbound.' + action, cloneContent(content, {
832
+ flow: {
833
+ ...outboundFlow,
834
+ sequenceId: getUniqueId(`${flowId}_${action}`),
835
+ ...(discardSequence ? {discardSequence: discardSequence.slice()} : undefined),
836
+ },
837
+ }));
838
+ }
839
+ return outboundList;
840
+ };
841
+
842
+ proto._onResumeMessage = function onResumeMessage(message) {
843
+ message.ack();
844
+
845
+ const stateMessage = this[kStateMessage];
846
+ const {fields} = stateMessage;
847
+
848
+ switch (fields.routingKey) {
849
+ case 'run.enter':
850
+ case 'run.start':
851
+ case 'run.discarded':
852
+ case 'run.end':
853
+ case 'run.leave':
854
+ break;
855
+ default:
856
+ return;
733
857
  }
734
858
 
735
- function shakeOutbound(sourceMessage) {
736
- const message = cloneMessage(sourceMessage);
737
- message.content.sequence = message.content.sequence || [];
738
- message.content.sequence.push({id, type});
859
+ if (!fields.redelivered) return;
739
860
 
740
- broker.publish('api', 'activity.shake.start', message.content, {persistent: false, type: 'shake'});
861
+ this.logger.debug(`<${this.id}> resume from ${message.content.status}`);
741
862
 
742
- if (isEnd) {
743
- return broker.publish('event', 'activity.shake.end', message.content, {persistent: false, type: 'shake'});
744
- }
863
+ return this.broker.publish('run', fields.routingKey, cloneContent(stateMessage.content), stateMessage.properties);
864
+ };
745
865
 
746
- outboundSequenceFlows.forEach((f) => f.shake(message));
747
- }
866
+ proto._publishEvent = function publishEvent(state, content, properties = {}) {
867
+ this.broker.publish('event', `activity.${state}`, cloneContent(content, {state}), {
868
+ ...properties,
869
+ type: state,
870
+ mandatory: state === 'error',
871
+ persistent: 'persistent' in properties ? properties.persistent : state !== 'stop',
872
+ });
873
+ };
748
874
 
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
- }
875
+ proto._onStop = function onStop(message) {
876
+ const running = this[kConsuming];
759
877
 
760
- function doOutbound(fromMessage, isDiscarded, callback) {
761
- if (!outboundSequenceFlows.length) return callback(null, []);
878
+ this.stopped = true;
762
879
 
763
- const fromContent = fromMessage.content;
880
+ this[kConsuming] = false;
881
+ const broker = this.broker;
882
+ broker.cancel('_activity-run');
883
+ broker.cancel('_activity-api');
884
+ broker.cancel('_activity-execution');
885
+ broker.cancel('_run-on-inbound');
886
+ broker.cancel('_format-consumer');
764
887
 
765
- let discardSequence = fromContent.discardSequence;
766
- if (isDiscarded && !discardSequence && attachedTo && fromContent.inbound && fromContent.inbound[0]) {
767
- discardSequence = [fromContent.inbound[0].id];
888
+ if (running) {
889
+ if (this.extensions) this.extensions.deactivate(message || this._createMessage());
890
+ this._publishEvent('stop', this._createMessage());
891
+ }
892
+ };
893
+
894
+ proto._consumeApi = function consumeApi() {
895
+ const executionId = this[kExec].executionId;
896
+ if (!executionId) return;
897
+ const broker = this.broker;
898
+ broker.cancel('_activity-api');
899
+ broker.subscribeTmp('api', `activity.*.${executionId}`, this[kMessageHandlers].onApiMessage, {noAck: true, consumerTag: '_activity-api', priority: 100});
900
+ };
901
+
902
+ proto._onApiMessage = function onApiMessage(routingKey, message) {
903
+ switch (message.properties.type) {
904
+ case 'discard': {
905
+ return this._discardRun(message);
768
906
  }
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()));
907
+ case 'stop': {
908
+ return this._onStop(message);
775
909
  }
776
-
777
- if (outboundFlows) {
778
- doRunOutbound(outboundFlows);
779
- return callback(null, outboundFlows);
910
+ case 'shake': {
911
+ return this._shakeOutbound(message);
780
912
  }
913
+ }
914
+ };
915
+
916
+ proto._createMessage = function createMessage(override) {
917
+ const name = this.name, status = this.status, parent = this.parent;
918
+ const result = {
919
+ ...override,
920
+ id: this.id,
921
+ type: this.type,
922
+ ...(name ? {name} : undefined),
923
+ ...(status ? {status} : undefined),
924
+ ...(parent ? {parent: cloneParent(parent)} : undefined),
925
+ };
781
926
 
782
- return evaluateOutbound(fromMessage, fromContent.outboundTakeOne, (err, evaluatedOutbound) => {
783
- if (err) return callback(new ActivityError(err.message, fromMessage, err));
927
+ for (const [flag, value] of Object.entries(this[kFlags])) {
928
+ if (value) result[flag] = value;
929
+ }
784
930
 
785
- const outbound = doRunOutbound(evaluatedOutbound);
786
- return callback(null, outbound);
787
- });
931
+ return result;
932
+ };
788
933
 
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
- }
934
+ proto._getOutboundSequenceFlowById = function getOutboundSequenceFlowById(flowId) {
935
+ return this[kFlows].outboundSequenceFlows.find((flow) => flow.id === flowId);
936
+ };
804
937
 
805
- function formatFlowAction(flow, options) {
806
- if (!options) options = {action: 'discard'};
938
+ proto._resumeExtensions = function resumeExtensions(message, callback) {
939
+ const extensions = this.extensions, bpmnIo = this.bpmnIo;
940
+ if (!extensions && !bpmnIo) return callback();
807
941
 
808
- const action = options.action;
809
- const message = options.message;
942
+ if (extensions) extensions.activate(cloneMessage(message), this);
943
+ if (bpmnIo) bpmnIo.activate(cloneMessage(message), this);
810
944
 
811
- return {
812
- ...options,
813
- id: flow.id,
814
- action,
815
- ...(flow.isDefault ? {isDefault: true} : undefined),
816
- ...(message !== undefined ? {message} : undefined),
817
- };
945
+ this.status = 'formatting';
946
+ return this.formatter.format(message, (err, formattedContent, formatted) => {
947
+ if (err) return callback(err);
948
+ return callback(null, formatted && formattedContent);
949
+ });
950
+ };
951
+
952
+ proto._deactivateRunConsumers = function _deactivateRunConsumers() {
953
+ const broker = this.broker;
954
+ broker.cancel('_activity-api');
955
+ broker.cancel('_activity-run');
956
+ broker.cancel('_activity-execution');
957
+ this[kConsuming] = false;
958
+ };
959
+
960
+ function OutboundEvaluator(activity, outboundFlows) {
961
+ this.activity = activity;
962
+ this.broker = activity.broker;
963
+ const flows = this.outboundFlows = outboundFlows.slice();
964
+ const defaultFlowIdx = flows.findIndex(({isDefault}) => isDefault);
965
+ if (defaultFlowIdx > -1) {
966
+ const [defaultFlow] = flows.splice(defaultFlowIdx, 1);
967
+ flows.push(defaultFlow);
818
968
  }
819
969
 
820
- function evaluateOutbound(fromMessage, discardRestAtTake, callback) {
821
- let conditionMet;
822
- const outbound = {};
823
-
824
- if (!outboundSequenceFlows.length) return completed();
970
+ this.defaultFlowIdx = outboundFlows.findIndex(({isDefault}) => isDefault);
971
+ this._onEvaluated = this.onEvaluated.bind(this);
972
+ this.evaluateArgs = {};
973
+ }
825
974
 
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;
975
+ OutboundEvaluator.prototype.evaluate = function evaluate(fromMessage, discardRestAtTake, callback) {
976
+ const outboundFlows = this.outboundFlows;
977
+
978
+ const args = this.evaluateArgs = {
979
+ fromMessage,
980
+ evaluationId: fromMessage.content.executionId,
981
+ discardRestAtTake,
982
+ callback,
983
+ conditionMet: false,
984
+ result: {},
985
+ takenCount: 0,
986
+ };
835
987
 
836
- broker.subscribeTmp('execution', 'evaluate.flow.#', (routingKey, {content: evalContent, ack}) => {
837
- const {id: flowId, action} = evalContent;
988
+ if (!outboundFlows.length) return this.completed();
838
989
 
839
- if (action === 'take') {
840
- takenCount++;
841
- conditionMet = true;
842
- }
990
+ const flows = args.flows = outboundFlows.slice();
843
991
 
844
- outbound[flowId] = evalContent;
992
+ this.broker.subscribeTmp('execution', 'evaluate.flow.#', this._onEvaluated, {
993
+ consumerTag: `_flow-evaluation-${args.evaluationId}`,
994
+ });
845
995
 
846
- if ('result' in evalContent) {
847
- logger.debug(`<${content.executionId} (${id})> flow <${flowId}> evaluated to: ${evalContent.result}`);
848
- }
996
+ return this.evaluateFlow(flows.shift());
997
+ };
849
998
 
850
- let nextFlow = evaluateFlows.shift();
851
- if (!nextFlow) return completed();
999
+ OutboundEvaluator.prototype.onEvaluated = function onEvaluated(routingKey, message) {
1000
+ const content = message.content;
1001
+ const {id: flowId, action, evaluationId} = message.content;
1002
+ const args = this.evaluateArgs;
852
1003
 
853
- if (discardRestAtTake && conditionMet) {
854
- do {
855
- outbound[nextFlow.id] = formatFlowAction(nextFlow, {action: 'discard'});
856
- } while ((nextFlow = evaluateFlows.shift()));
857
- return completed();
858
- }
1004
+ if (action === 'take') {
1005
+ args.takenCount++;
1006
+ args.conditionMet = true;
1007
+ }
859
1008
 
860
- if (conditionMet && nextFlow.isDefault) {
861
- outbound[nextFlow.id] = formatFlowAction(nextFlow, {action: 'discard'});
862
- return completed();
863
- }
1009
+ args.result[flowId] = content;
864
1010
 
865
- ack();
866
- evaluateSequenceFlows(nextFlow);
867
- }, {consumerTag: `_flow-evaluation-${executionId}`});
1011
+ if ('result' in content) {
1012
+ this.activity.logger.debug(`<${evaluationId} (${this.activity.id})> flow <${flowId}> evaluated to: ${!!content.result}`);
1013
+ }
868
1014
 
869
- return evaluateSequenceFlows(evaluateFlows.shift());
1015
+ let nextFlow = args.flows.shift();
1016
+ if (!nextFlow) return this.completed();
870
1017
 
871
- function completed(err) {
872
- broker.cancel(`_flow-evaluation-${executionId}`);
873
- if (err) return callback(err);
1018
+ if (args.discardRestAtTake && args.conditionMet) {
1019
+ do {
1020
+ args.result[nextFlow.id] = formatFlowAction(nextFlow, {action: 'discard'});
1021
+ } while ((nextFlow = args.flows.shift()));
1022
+ return this.completed();
1023
+ }
874
1024
 
875
- if (!takenCount) {
876
- const nonTakenError = new ActivityError(`<${id}> no conditional flow taken`, fromMessage);
877
- logger.error(`<${id}>`, nonTakenError);
878
- return callback(nonTakenError);
879
- }
1025
+ if (args.conditionMet && nextFlow.isDefault) {
1026
+ args.result[nextFlow.id] = formatFlowAction(nextFlow, {action: 'discard'});
1027
+ return this.completed();
1028
+ }
880
1029
 
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
- }, []);
1030
+ message.ack();
1031
+ this.evaluateFlow(nextFlow);
1032
+ };
889
1033
 
890
- return callback(null, outboundList);
891
- }
1034
+ OutboundEvaluator.prototype.evaluateFlow = function evaluateFlow(flow) {
1035
+ const broker = this.broker;
1036
+ if (flow.isDefault) {
1037
+ return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {action: 'take'}), {persistent: false});
1038
+ }
892
1039
 
893
- function evaluateSequenceFlows(flow) {
894
- if (!flow) return completed();
1040
+ const flowCondition = flow.getCondition();
1041
+ if (!flowCondition) {
1042
+ return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {action: 'take'}), {persistent: false});
1043
+ }
895
1044
 
896
- if (flow.isDefault) {
897
- return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {action: 'take'}), {persistent: false});
898
- }
1045
+ const {fromMessage, evaluationId} = this.evaluateArgs;
1046
+ flowCondition.execute(cloneMessage(fromMessage), (err, result) => {
1047
+ if (err) return this.completed(err);
1048
+ const action = result ? 'take' : 'discard';
1049
+ return broker.publish('execution', 'evaluate.flow.' + action, formatFlowAction(flow, {
1050
+ action,
1051
+ result,
1052
+ evaluationId,
1053
+ }), {persistent: false});
1054
+ });
1055
+ };
899
1056
 
900
- const flowCondition = flow.getCondition();
901
- if (!flowCondition) {
902
- return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {action: 'take'}), {persistent: false});
903
- }
1057
+ OutboundEvaluator.prototype.completed = function completed(err) {
1058
+ const {callback, evaluationId, fromMessage, result, takenCount} = this.evaluateArgs;
1059
+ this.broker.cancel(`_flow-evaluation-${evaluationId}`);
904
1060
 
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
- }
1061
+ if (err) return callback(err);
915
1062
 
916
- function getActivityById(elementId) {
917
- return context.getActivityById(elementId);
1063
+ if (!takenCount && this.outboundFlows.length) {
1064
+ const nonTakenError = new ActivityError(`<${this.activity.id}> no conditional flow taken`, fromMessage);
1065
+ return callback(nonTakenError);
918
1066
  }
919
1067
 
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
- };
1068
+ const message = fromMessage.content.message;
1069
+ const evaluationResult = [];
1070
+ for (const flow of Object.values(result)) {
1071
+ evaluationResult.push({
1072
+ ...flow,
1073
+ ...(message !== undefined ? {message} : undefined),
1074
+ });
933
1075
  }
934
1076
 
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
- }
1077
+ return callback(null, evaluationResult);
1078
+ };
944
1079
 
945
- function getApi(message) {
946
- if (execution && !execution.completed) return execution.getApi(message);
947
- return ActivityApi(broker, message || stateMessage);
948
- }
1080
+ function formatFlowAction(flow, options) {
1081
+ return {
1082
+ ...options,
1083
+ id: flow.id,
1084
+ action: options.action,
1085
+ ...(flow.isDefault ? {isDefault: true} : undefined),
1086
+ };
949
1087
  }