bpmn-elements 18.0.1 → 18.0.2

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.
@@ -97,8 +97,9 @@ function Activity(Behaviour, activityDef, context) {
97
97
  outboundSequenceFlows,
98
98
  outboundEvaluator: new _outboundEvaluator.OutboundEvaluator(this, outboundSequenceFlows)
99
99
  };
100
+ const isThrowingLink = activityDef.isThrowing && activityDef.linkNames?.length;
100
101
  this[K_FLAGS] = {
101
- isEnd: !outboundSequenceFlows.length,
102
+ isEnd: !outboundSequenceFlows.length && !isThrowingLink,
102
103
  isStart: !hasInboundTrigger && !behaviour.triggeredByEvent && !activityDef.isCatching,
103
104
  isSubProcess: activityDef.isSubProcess,
104
105
  isMultiInstance: !!behaviour.loopCharacteristics,
@@ -268,7 +269,7 @@ Object.defineProperties(Activity.prototype, {
268
269
  },
269
270
  initialized: {
270
271
  get() {
271
- return !!this[K_EXEC]?.get('initExecutionId');
272
+ return this[K_EXEC].get('initialized') > 0;
272
273
  }
273
274
  }
274
275
  });
@@ -280,7 +281,23 @@ Object.defineProperties(Activity.prototype, {
280
281
  Activity.prototype.activate = function activate() {
281
282
  if (this[_constants.K_ACTIVATED]) return;
282
283
  this[_constants.K_ACTIVATED] = true;
283
- return this.addInboundListeners() && this._consumeInbound();
284
+ this.addInboundListeners();
285
+ return this.consumeInbound();
286
+ };
287
+
288
+ /**
289
+ * Assert the inbound queue consumer when the activity has a trigger or is initialized.
290
+ * Idempotent: asserting the consumer again while one is active is a no-op.
291
+ * @returns {void}
292
+ */
293
+ Activity.prototype.consumeInbound = function consumeInbound() {
294
+ if (!this[_constants.K_ACTIVATED]) return;
295
+ if (this.status) return;
296
+ if (!this._getInboundTriggers().length && !this.initialized) return;
297
+ const onInbound = this[_constants.K_MESSAGE_HANDLERS].onInbound;
298
+ return this.broker.getQueue('inbound-q').assertConsumer(onInbound, {
299
+ consumerTag: '_run-on-inbound'
300
+ });
284
301
  };
285
302
 
286
303
  /** @internal */
@@ -326,17 +343,28 @@ Activity.prototype.deactivate = function deactivate() {
326
343
  /**
327
344
  * Initialise activity executionId and emit init event without starting the run.
328
345
  * @param {Record<string, any>} [initContent] Optional content merged into the init message
346
+ * @param {import('smqp').MessageProperties} [properties] Optional message properties merged into the init message properties
329
347
  */
330
- Activity.prototype.init = function init(initContent) {
348
+ Activity.prototype.init = function init(initContent, properties) {
331
349
  const id = this.id;
332
350
  const exec = this[K_EXEC];
333
- const executionId = exec.has('initExecutionId') ? exec.get('initExecutionId') : (0, _shared.getUniqueId)(id);
334
- exec.set('initExecutionId', executionId);
351
+ exec.set('initialized', (exec.get('initialized') || 0) + 1);
352
+ const executionId = (0, _shared.getUniqueId)(id);
335
353
  this.logger.debug(`<${id}> initialized with executionId <${executionId}>`);
336
354
  this._publishEvent('init', this._createMessage({
337
355
  ...initContent,
338
356
  executionId
339
357
  }));
358
+ this.broker.getQueue('inbound-q').queueMessage({
359
+ routingKey: 'activity.init'
360
+ }, {
361
+ ...initContent,
362
+ id,
363
+ executionId
364
+ }, {
365
+ persistent: false,
366
+ ...properties
367
+ });
340
368
  };
341
369
 
342
370
  /**
@@ -347,13 +375,15 @@ Activity.prototype.init = function init(initContent) {
347
375
  Activity.prototype.run = function run(runContent) {
348
376
  const id = this.id;
349
377
  if (this.isRunning) throw new Error(`activity <${id}> is already running`);
350
- const exec = this[K_EXEC];
351
- const executionId = exec.get('initExecutionId') || (0, _shared.getUniqueId)(id);
352
- exec.set('executionId', executionId);
353
- exec.delete('initExecutionId');
378
+ const {
379
+ initExecutionId,
380
+ ...runMessage
381
+ } = runContent || {};
382
+ const executionId = runMessage?.id === id && initExecutionId ? initExecutionId : (0, _shared.getUniqueId)(id);
383
+ this[K_EXEC].set('executionId', executionId);
354
384
  this._consumeApi();
355
385
  const content = this._createMessage({
356
- ...runContent,
386
+ ...runMessage,
357
387
  executionId
358
388
  });
359
389
  const broker = this.broker;
@@ -558,10 +588,8 @@ Activity.prototype.getActivityById = function getActivityById(elementId) {
558
588
 
559
589
  /** @internal */
560
590
  Activity.prototype._runDiscard = function runDiscard(discardContent) {
561
- const exec = this[K_EXEC];
562
- const executionId = exec.get('initExecutionId') || (0, _shared.getUniqueId)(this.id);
563
- exec.set('executionId', executionId);
564
- exec.delete('initExecutionId');
591
+ const executionId = (0, _shared.getUniqueId)(this.id);
592
+ this[K_EXEC].set('executionId', executionId);
565
593
  this._consumeApi();
566
594
  const content = this._createMessage({
567
595
  ...discardContent,
@@ -613,7 +641,7 @@ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) {
613
641
  id: this.id,
614
642
  type: this.type
615
643
  });
616
- return this.broker.publish('event', 'activity.shake.join', message.content, {
644
+ return this.broker.publish('event', 'activity.shake.converge', message.content, {
617
645
  persistent: false,
618
646
  type: 'shake'
619
647
  });
@@ -674,43 +702,38 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) {
674
702
  for (const t of targets.values()) t.shake(message);
675
703
  };
676
704
 
677
- /** @internal */
678
- Activity.prototype._consumeInbound = function consumeInbound() {
679
- if (!this[_constants.K_ACTIVATED]) return;
680
- if (this.status || !this._getInboundTriggers().length) return;
681
- const inboundQ = this.broker.getQueue('inbound-q');
682
- const onInbound = this[_constants.K_MESSAGE_HANDLERS].onInbound;
683
- return inboundQ.assertConsumer(onInbound, {
684
- consumerTag: '_run-on-inbound'
685
- });
686
- };
687
-
688
705
  /** @internal */
689
706
  Activity.prototype._onInbound = function onInbound(routingKey, message) {
690
707
  message.ack();
691
708
  const broker = this.broker;
692
709
  broker.cancel('_run-on-inbound');
693
710
  const content = message.content;
694
- const inbound = [(0, _messageHelper.cloneContent)(content)];
695
711
  switch (routingKey) {
696
- case 'activity.relink':
697
- if (content.executionId) this[K_EXEC].set('initExecutionId', content.executionId);
698
- return this.run({
699
- message: content.message,
700
- inbound
701
- });
712
+ case 'activity.init':
713
+ {
714
+ const exec = this[K_EXEC];
715
+ exec.set('initialized', (exec.get('initialized') || 0) - 1);
716
+ return this.run({
717
+ initExecutionId: content.executionId,
718
+ id: content.id,
719
+ message: content.message,
720
+ ...(content.inbound?.length && {
721
+ inbound: content.inbound
722
+ })
723
+ });
724
+ }
702
725
  case 'association.take':
703
726
  case 'flow.take':
704
727
  case 'activity.restart':
705
728
  case 'activity.enter':
706
729
  return this.run({
707
730
  message: content.message,
708
- inbound
731
+ inbound: [(0, _messageHelper.cloneContent)(content)]
709
732
  });
710
733
  case 'activity.discard':
711
734
  {
712
735
  return this._runDiscard({
713
- inbound
736
+ inbound: [(0, _messageHelper.cloneContent)(content)]
714
737
  });
715
738
  }
716
739
  }
@@ -740,26 +763,9 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message
740
763
  {
741
764
  const linkName = content.message?.linkName;
742
765
  if (!this[K_FLAGS].linkNames?.includes(linkName)) break;
743
- const executionId = (0, _shared.getUniqueId)(this.id);
744
- this.broker.publish('event', 'activity.enter', (0, _messageHelper.cloneContent)(content, {
745
- id: this.id,
746
- type: this.type,
747
- executionId,
748
- state: 'enter',
749
- message: {
750
- ...content.message
751
- }
752
- }));
753
- inboundQ.queueMessage({
754
- routingKey: 'activity.relink'
755
- }, (0, _messageHelper.cloneContent)(content, {
756
- id: this.id,
757
- executionId,
758
- message: {
759
- ...content.message
760
- }
761
- }), properties);
762
- return;
766
+ return this.init({
767
+ inbound: [(0, _messageHelper.cloneContent)(content)]
768
+ });
763
769
  }
764
770
  case 'association.take':
765
771
  case 'flow.take':
@@ -942,7 +948,7 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey,
942
948
  case 'run.next':
943
949
  message.ack();
944
950
  this._pauseRunQ();
945
- return this._consumeInbound();
951
+ return this.consumeInbound();
946
952
  }
947
953
  if (!step) message.ack();
948
954
  };
@@ -44,9 +44,9 @@ Object.defineProperty(BoundaryEventBehaviour.prototype, 'executionId', {
44
44
  }
45
45
  });
46
46
  Object.defineProperty(BoundaryEventBehaviour.prototype, 'cancelActivity', {
47
+ /** @returns {boolean} */
47
48
  get() {
48
- const behaviour = this.activity.behaviour || {};
49
- return 'cancelActivity' in behaviour ? behaviour.cancelActivity : true;
49
+ return this.activity.behaviour?.cancelActivity ?? true;
50
50
  }
51
51
  });
52
52
 
@@ -76,11 +76,15 @@ function ParallelGatewayBehaviour(activity) {
76
76
  this.type = activity.type;
77
77
  this.activity = activity;
78
78
  this.broker = activity.broker;
79
+ /**
80
+ * Inbound taken sequence flow sequences
81
+ * @type {Set<import('#types').ElementMessageContent}
82
+ */
79
83
  this.inbound = new Set();
80
- this.isConverging = true;
81
84
  this[_constants.K_EXECUTE_MESSAGE] = undefined;
82
85
  }
83
86
  Object.defineProperty(ParallelGatewayBehaviour.prototype, 'executionId', {
87
+ /** @returns {string | undefined} */
84
88
  get() {
85
89
  return this[_constants.K_EXECUTE_MESSAGE]?.content.executionId;
86
90
  }
@@ -110,6 +114,12 @@ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) {
110
114
  }
111
115
  }
112
116
  };
117
+
118
+ /**
119
+ * Setup peer monitor
120
+ * @param {import('#types').ElementBrokerMessage} executeMessage
121
+ * @returns {void}
122
+ */
113
123
  ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) {
114
124
  const peerIds = new Set([...this.activity[K_PEERS].values()].map(v => [...v]).flat());
115
125
  this[_constants.K_TARGETS] = new Map([...peerIds].map(pid => [pid, this.activity.getActivityById(pid)]));
@@ -142,9 +152,7 @@ ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) {
142
152
  exclusive: true,
143
153
  prefetch: 10000
144
154
  });
145
- if (this.isConverging) {
146
- this.broker.publish('event', 'activity.converge', (0, _messageHelper.cloneContent)(executeContent));
147
- }
155
+ this.broker.publish('event', 'activity.converge', (0, _messageHelper.cloneContent)(executeContent));
148
156
  return this.broker.publish('execution', 'execute.start', (0, _messageHelper.cloneContent)(executeMessage.content, {
149
157
  preventComplete: true,
150
158
  state: STATE_SETUP
@@ -179,17 +187,19 @@ ParallelGatewayBehaviour.prototype._stop = function stop() {
179
187
  this.broker.cancel('_parallel-execution-peer-enter-tag');
180
188
  this.peerMonitor.stop();
181
189
  };
190
+
191
+ /**
192
+ * Peer monitor
193
+ * @param {import('#types').Activity} activity parallel gateway activity
194
+ * @param {Map<string, import('#types').Activity} targets parallel gateway peer target activities
195
+ */
182
196
  function PeerMonitor(activity, targets) {
183
197
  this.activity = activity;
184
198
  this.id = activity.id;
185
199
  this.broker = activity.broker;
186
- this.running = 0;
187
- this.index = 0;
188
- this.discarded = 0;
189
200
  this.running = new Map();
190
201
  this.watching = new Map();
191
202
  this.targets = targets;
192
- this.touched = new Set();
193
203
  this.inbound = [];
194
204
  }
195
205
  Object.defineProperty(PeerMonitor.prototype, 'isRunning', {
@@ -197,6 +207,12 @@ Object.defineProperty(PeerMonitor.prototype, 'isRunning', {
197
207
  return this.running.size > 0;
198
208
  }
199
209
  });
210
+
211
+ /**
212
+ * Execute peer monitor
213
+ * @param {import('#types').ElementBrokerMessage} executeMessage
214
+ * @returns {number} number of running peers
215
+ */
200
216
  PeerMonitor.prototype.execute = function execute(executeMessage) {
201
217
  const message = (0, _messageHelper.cloneMessage)(executeMessage);
202
218
  const inbound = message.content.inbound.pop();
@@ -208,12 +224,16 @@ PeerMonitor.prototype.execute = function execute(executeMessage) {
208
224
  state: STATE_MONTITORING,
209
225
  preventComplete: true
210
226
  });
211
- this.touched.add(inbound.sourceId);
212
227
  for (const target of this.targets.values()) {
213
228
  this.monitor(target);
214
229
  }
215
230
  return this.running.size;
216
231
  };
232
+
233
+ /**
234
+ * Monitor peer activity
235
+ * @param {import('#types').Activity} peerActivity
236
+ */
217
237
  PeerMonitor.prototype.monitor = function monitor(peerActivity) {
218
238
  if (this.watching.has(peerActivity.id)) return;
219
239
  this.activity.logger.debug(`<${this.id}> monitor <${peerActivity.id}> with status: ${peerActivity.status}`);
@@ -391,7 +391,7 @@ ProcessExecution.prototype._start = function start() {
391
391
  this._shakeOnStart();
392
392
  for (const a of startActivities) a.init();
393
393
  this[_constants.K_STATUS] = 'executing';
394
- for (const a of startActivities) a.run();
394
+ for (const a of startActivities) a.consumeInbound();
395
395
  if (!startActivities.size) {
396
396
  for (const a of this[K_ELEMENTS].triggeredByEvent) {
397
397
  if (a.isCatching && !a.isRunning) a.run();
@@ -556,7 +556,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) {
556
556
  }) => {
557
557
  if (content.parent.id !== this.id) return;
558
558
  switch (routingKey) {
559
- case 'activity.shake.join':
559
+ case 'activity.shake.converge':
560
560
  {
561
561
  const join = convergingGateways.get(content.join);
562
562
  if (!join) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bpmn-elements",
3
- "version": "18.0.1",
3
+ "version": "18.0.2",
4
4
  "description": "Executable workflow elements based on BPMN 2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -91,8 +91,10 @@ export function Activity(Behaviour, activityDef, context) {
91
91
  outboundEvaluator: new OutboundEvaluator(this, outboundSequenceFlows),
92
92
  };
93
93
 
94
+ const isThrowingLink = activityDef.isThrowing && activityDef.linkNames?.length;
95
+
94
96
  this[K_FLAGS] = {
95
- isEnd: !outboundSequenceFlows.length,
97
+ isEnd: !outboundSequenceFlows.length && !isThrowingLink,
96
98
  isStart: !hasInboundTrigger && !behaviour.triggeredByEvent && !activityDef.isCatching,
97
99
  isSubProcess: activityDef.isSubProcess,
98
100
  isMultiInstance: !!behaviour.loopCharacteristics,
@@ -262,7 +264,7 @@ Object.defineProperties(Activity.prototype, {
262
264
  },
263
265
  initialized: {
264
266
  get() {
265
- return !!this[K_EXEC]?.get('initExecutionId');
267
+ return this[K_EXEC].get('initialized') > 0;
266
268
  },
267
269
  },
268
270
  });
@@ -274,7 +276,25 @@ Object.defineProperties(Activity.prototype, {
274
276
  Activity.prototype.activate = function activate() {
275
277
  if (this[K_ACTIVATED]) return;
276
278
  this[K_ACTIVATED] = true;
277
- return this.addInboundListeners() && this._consumeInbound();
279
+ this.addInboundListeners();
280
+ return this.consumeInbound();
281
+ };
282
+
283
+ /**
284
+ * Assert the inbound queue consumer when the activity has a trigger or is initialized.
285
+ * Idempotent: asserting the consumer again while one is active is a no-op.
286
+ * @returns {void}
287
+ */
288
+ Activity.prototype.consumeInbound = function consumeInbound() {
289
+ if (!this[K_ACTIVATED]) return;
290
+
291
+ if (this.status) return;
292
+
293
+ if (!this._getInboundTriggers().length && !this.initialized) return;
294
+
295
+ const onInbound = this[K_MESSAGE_HANDLERS].onInbound;
296
+
297
+ return this.broker.getQueue('inbound-q').assertConsumer(onInbound, { consumerTag: '_run-on-inbound' });
278
298
  };
279
299
 
280
300
  /** @internal */
@@ -319,14 +339,18 @@ Activity.prototype.deactivate = function deactivate() {
319
339
  /**
320
340
  * Initialise activity executionId and emit init event without starting the run.
321
341
  * @param {Record<string, any>} [initContent] Optional content merged into the init message
342
+ * @param {import('smqp').MessageProperties} [properties] Optional message properties merged into the init message properties
322
343
  */
323
- Activity.prototype.init = function init(initContent) {
344
+ Activity.prototype.init = function init(initContent, properties) {
324
345
  const id = this.id;
325
346
  const exec = this[K_EXEC];
326
- const executionId = exec.has('initExecutionId') ? exec.get('initExecutionId') : getUniqueId(id);
327
- exec.set('initExecutionId', executionId);
347
+ exec.set('initialized', (exec.get('initialized') || 0) + 1);
348
+ const executionId = getUniqueId(id);
328
349
  this.logger.debug(`<${id}> initialized with executionId <${executionId}>`);
329
350
  this._publishEvent('init', this._createMessage({ ...initContent, executionId }));
351
+ this.broker
352
+ .getQueue('inbound-q')
353
+ .queueMessage({ routingKey: 'activity.init' }, { ...initContent, id, executionId }, { persistent: false, ...properties });
330
354
  };
331
355
 
332
356
  /**
@@ -338,14 +362,13 @@ Activity.prototype.run = function run(runContent) {
338
362
  const id = this.id;
339
363
  if (this.isRunning) throw new Error(`activity <${id}> is already running`);
340
364
 
341
- const exec = this[K_EXEC];
342
- const executionId = exec.get('initExecutionId') || getUniqueId(id);
343
- exec.set('executionId', executionId);
344
- exec.delete('initExecutionId');
365
+ const { initExecutionId, ...runMessage } = runContent || {};
366
+ const executionId = runMessage?.id === id && initExecutionId ? initExecutionId : getUniqueId(id);
367
+ this[K_EXEC].set('executionId', executionId);
345
368
 
346
369
  this._consumeApi();
347
370
 
348
- const content = this._createMessage({ ...runContent, executionId });
371
+ const content = this._createMessage({ ...runMessage, executionId });
349
372
  const broker = this.broker;
350
373
 
351
374
  broker.publish('run', 'run.enter', content);
@@ -541,10 +564,8 @@ Activity.prototype.getActivityById = function getActivityById(elementId) {
541
564
 
542
565
  /** @internal */
543
566
  Activity.prototype._runDiscard = function runDiscard(discardContent) {
544
- const exec = this[K_EXEC];
545
- const executionId = exec.get('initExecutionId') || getUniqueId(this.id);
546
- exec.set('executionId', executionId);
547
- exec.delete('initExecutionId');
567
+ const executionId = getUniqueId(this.id);
568
+ this[K_EXEC].set('executionId', executionId);
548
569
 
549
570
  this._consumeApi();
550
571
 
@@ -594,7 +615,7 @@ Activity.prototype._onShakeMessage = function _onShakeMessage(sourceMessage) {
594
615
  if (this[K_FLAGS].isParallelGateway) {
595
616
  const message = cloneMessage(sourceMessage, { join: this.id });
596
617
  message.content.sequence.push({ id: this.id, type: this.type });
597
- return this.broker.publish('event', 'activity.shake.join', message.content, {
618
+ return this.broker.publish('event', 'activity.shake.converge', message.content, {
598
619
  persistent: false,
599
620
  type: 'shake',
600
621
  });
@@ -641,18 +662,6 @@ Activity.prototype._shakeOutbound = function shakeOutbound(sourceMessage) {
641
662
  for (const t of targets.values()) t.shake(message);
642
663
  };
643
664
 
644
- /** @internal */
645
- Activity.prototype._consumeInbound = function consumeInbound() {
646
- if (!this[K_ACTIVATED]) return;
647
-
648
- if (this.status || !this._getInboundTriggers().length) return;
649
-
650
- const inboundQ = this.broker.getQueue('inbound-q');
651
- const onInbound = this[K_MESSAGE_HANDLERS].onInbound;
652
-
653
- return inboundQ.assertConsumer(onInbound, { consumerTag: '_run-on-inbound' });
654
- };
655
-
656
665
  /** @internal */
657
666
  Activity.prototype._onInbound = function onInbound(routingKey, message) {
658
667
  message.ack();
@@ -660,25 +669,28 @@ Activity.prototype._onInbound = function onInbound(routingKey, message) {
660
669
  broker.cancel('_run-on-inbound');
661
670
 
662
671
  const content = message.content;
663
- const inbound = [cloneContent(content)];
664
672
 
665
673
  switch (routingKey) {
666
- case 'activity.relink':
667
- if (content.executionId) this[K_EXEC].set('initExecutionId', content.executionId);
674
+ case 'activity.init': {
675
+ const exec = this[K_EXEC];
676
+ exec.set('initialized', (exec.get('initialized') || 0) - 1);
668
677
  return this.run({
678
+ initExecutionId: content.executionId,
679
+ id: content.id,
669
680
  message: content.message,
670
- inbound,
681
+ ...(content.inbound?.length && { inbound: content.inbound }),
671
682
  });
683
+ }
672
684
  case 'association.take':
673
685
  case 'flow.take':
674
686
  case 'activity.restart':
675
687
  case 'activity.enter':
676
688
  return this.run({
677
689
  message: content.message,
678
- inbound,
690
+ inbound: [cloneContent(content)],
679
691
  });
680
692
  case 'activity.discard': {
681
- return this._runDiscard({ inbound });
693
+ return this._runDiscard({ inbound: [cloneContent(content)] });
682
694
  }
683
695
  }
684
696
  };
@@ -702,18 +714,7 @@ Activity.prototype._onInboundEvent = function onInboundEvent(routingKey, message
702
714
  case 'activity.link': {
703
715
  const linkName = content.message?.linkName;
704
716
  if (!this[K_FLAGS].linkNames?.includes(linkName)) break;
705
- const executionId = getUniqueId(this.id);
706
- this.broker.publish(
707
- 'event',
708
- 'activity.enter',
709
- cloneContent(content, { id: this.id, type: this.type, executionId, state: 'enter', message: { ...content.message } })
710
- );
711
- inboundQ.queueMessage(
712
- { routingKey: 'activity.relink' },
713
- cloneContent(content, { id: this.id, executionId, message: { ...content.message } }),
714
- properties
715
- );
716
- return;
717
+ return this.init({ inbound: [cloneContent(content)] });
717
718
  }
718
719
  case 'association.take':
719
720
  case 'flow.take':
@@ -890,7 +891,7 @@ Activity.prototype._continueRunMessage = function continueRunMessage(routingKey,
890
891
  case 'run.next':
891
892
  message.ack();
892
893
  this._pauseRunQ();
893
- return this._consumeInbound();
894
+ return this.consumeInbound();
894
895
  }
895
896
 
896
897
  if (!step) message.ack();
@@ -41,9 +41,9 @@ Object.defineProperty(BoundaryEventBehaviour.prototype, 'executionId', {
41
41
  });
42
42
 
43
43
  Object.defineProperty(BoundaryEventBehaviour.prototype, 'cancelActivity', {
44
+ /** @returns {boolean} */
44
45
  get() {
45
- const behaviour = this.activity.behaviour || {};
46
- return 'cancelActivity' in behaviour ? behaviour.cancelActivity : true;
46
+ return this.activity.behaviour?.cancelActivity ?? true;
47
47
  },
48
48
  });
49
49
 
@@ -74,13 +74,17 @@ export function ParallelGatewayBehaviour(activity) {
74
74
  this.type = activity.type;
75
75
  this.activity = activity;
76
76
  this.broker = activity.broker;
77
+ /**
78
+ * Inbound taken sequence flow sequences
79
+ * @type {Set<import('#types').ElementMessageContent}
80
+ */
77
81
  this.inbound = new Set();
78
82
 
79
- this.isConverging = true;
80
83
  this[K_EXECUTE_MESSAGE] = undefined;
81
84
  }
82
85
 
83
86
  Object.defineProperty(ParallelGatewayBehaviour.prototype, 'executionId', {
87
+ /** @returns {string | undefined} */
84
88
  get() {
85
89
  return this[K_EXECUTE_MESSAGE]?.content.executionId;
86
90
  },
@@ -112,6 +116,11 @@ ParallelGatewayBehaviour.prototype.execute = function execute(executeMessage) {
112
116
  }
113
117
  };
114
118
 
119
+ /**
120
+ * Setup peer monitor
121
+ * @param {import('#types').ElementBrokerMessage} executeMessage
122
+ * @returns {void}
123
+ */
115
124
  ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) {
116
125
  const peerIds = new Set([...this.activity[K_PEERS].values()].map((v) => [...v]).flat());
117
126
  this[K_TARGETS] = new Map([...peerIds].map((pid) => [pid, this.activity.getActivityById(pid)]));
@@ -152,9 +161,7 @@ ParallelGatewayBehaviour.prototype.setup = function setup(executeMessage) {
152
161
  { consumerTag: '_converging-inbound', exclusive: true, prefetch: 10000 }
153
162
  );
154
163
 
155
- if (this.isConverging) {
156
- this.broker.publish('event', 'activity.converge', cloneContent(executeContent));
157
- }
164
+ this.broker.publish('event', 'activity.converge', cloneContent(executeContent));
158
165
 
159
166
  return this.broker.publish(
160
167
  'execution',
@@ -197,17 +204,18 @@ ParallelGatewayBehaviour.prototype._stop = function stop() {
197
204
  this.peerMonitor.stop();
198
205
  };
199
206
 
207
+ /**
208
+ * Peer monitor
209
+ * @param {import('#types').Activity} activity parallel gateway activity
210
+ * @param {Map<string, import('#types').Activity} targets parallel gateway peer target activities
211
+ */
200
212
  function PeerMonitor(activity, targets) {
201
213
  this.activity = activity;
202
214
  this.id = activity.id;
203
215
  this.broker = activity.broker;
204
- this.running = 0;
205
- this.index = 0;
206
- this.discarded = 0;
207
216
  this.running = new Map();
208
217
  this.watching = new Map();
209
218
  this.targets = targets;
210
- this.touched = new Set();
211
219
  this.inbound = [];
212
220
  }
213
221
 
@@ -217,6 +225,11 @@ Object.defineProperty(PeerMonitor.prototype, 'isRunning', {
217
225
  },
218
226
  });
219
227
 
228
+ /**
229
+ * Execute peer monitor
230
+ * @param {import('#types').ElementBrokerMessage} executeMessage
231
+ * @returns {number} number of running peers
232
+ */
220
233
  PeerMonitor.prototype.execute = function execute(executeMessage) {
221
234
  const message = cloneMessage(executeMessage);
222
235
  const inbound = message.content.inbound.pop();
@@ -231,8 +244,6 @@ PeerMonitor.prototype.execute = function execute(executeMessage) {
231
244
  preventComplete: true,
232
245
  });
233
246
 
234
- this.touched.add(inbound.sourceId);
235
-
236
247
  for (const target of this.targets.values()) {
237
248
  this.monitor(target);
238
249
  }
@@ -240,6 +251,10 @@ PeerMonitor.prototype.execute = function execute(executeMessage) {
240
251
  return this.running.size;
241
252
  };
242
253
 
254
+ /**
255
+ * Monitor peer activity
256
+ * @param {import('#types').Activity} peerActivity
257
+ */
243
258
  PeerMonitor.prototype.monitor = function monitor(peerActivity) {
244
259
  if (this.watching.has(peerActivity.id)) return;
245
260
 
@@ -400,7 +400,7 @@ ProcessExecution.prototype._start = function start() {
400
400
 
401
401
  for (const a of startActivities) a.init();
402
402
  this[K_STATUS] = 'executing';
403
- for (const a of startActivities) a.run();
403
+ for (const a of startActivities) a.consumeInbound();
404
404
 
405
405
  if (!startActivities.size) {
406
406
  for (const a of this[K_ELEMENTS].triggeredByEvent) {
@@ -571,7 +571,7 @@ ProcessExecution.prototype._shakeElements = function shakeElements(fromId) {
571
571
  if (content.parent.id !== this.id) return;
572
572
 
573
573
  switch (routingKey) {
574
- case 'activity.shake.join': {
574
+ case 'activity.shake.converge': {
575
575
  const join = convergingGateways.get(content.join);
576
576
  if (!join) {
577
577
  convergingGateways.set(content.join, content);
package/types/index.d.ts CHANGED
@@ -580,6 +580,11 @@ declare module 'bpmn-elements' {
580
580
  * Subscribe to inbound flows and start consuming the inbound queue.
581
581
  * */
582
582
  activate(): void;
583
+ /**
584
+ * Assert the inbound queue consumer when the activity has a trigger or is initialized.
585
+ * Idempotent: asserting the consumer again while one is active is a no-op.
586
+ * */
587
+ consumeInbound(): void;
583
588
  /**
584
589
  * Cancel inbound subscriptions and any pending run/format consumers.
585
590
  */
@@ -587,8 +592,9 @@ declare module 'bpmn-elements' {
587
592
  /**
588
593
  * Initialise activity executionId and emit init event without starting the run.
589
594
  * @param initContent Optional content merged into the init message
595
+ * @param properties Optional message properties merged into the init message properties
590
596
  */
591
- init(initContent?: Record<string, any>): void;
597
+ init(initContent?: Record<string, any>, properties?: import("smqp").MessageProperties): void;
592
598
  /**
593
599
  * Start running the activity by publishing run.enter and run.start.
594
600
  * @param runContent Optional content merged into the run message
@@ -1950,7 +1956,7 @@ declare module 'bpmn-elements' {
1950
1956
  environment: Environment;
1951
1957
  broker: ElementBroker<Activity>;
1952
1958
  get executionId(): string | undefined;
1953
- get cancelActivity(): any;
1959
+ get cancelActivity(): boolean;
1954
1960
 
1955
1961
  execute(executeMessage: ElementBrokerMessage): void;
1956
1962
  }
@@ -2106,29 +2112,48 @@ declare module 'bpmn-elements' {
2106
2112
  type: string;
2107
2113
  activity: Activity;
2108
2114
  broker: ElementBroker<Activity>;
2109
- inbound: Set<any>;
2110
- isConverging: boolean;
2111
- get executionId(): any;
2115
+ /**
2116
+ * Inbound taken sequence flow sequences
2117
+ * */
2118
+ inbound: Set<ElementMessageContent>;
2119
+ get executionId(): string | undefined;
2112
2120
 
2113
2121
  execute(executeMessage: ElementBrokerMessage): void;
2114
- setup(executeMessage: any): number | undefined;
2122
+ /**
2123
+ * Setup peer monitor
2124
+ * */
2125
+ setup(executeMessage: ElementBrokerMessage): void;
2115
2126
  peerMonitor: PeerMonitor | undefined;
2116
2127
  }
2128
+ /**
2129
+ * Peer monitor
2130
+ * @param activity parallel gateway activity
2131
+ * @param targets parallel gateway peer target activities
2132
+ */
2117
2133
  class PeerMonitor {
2118
- constructor(activity: any, targets: any);
2119
- activity: any;
2120
- id: any;
2121
- broker: any;
2134
+ /**
2135
+ * Peer monitor
2136
+ * @param activity parallel gateway activity
2137
+ * @param targets parallel gateway peer target activities
2138
+ */
2139
+ constructor(activity: Activity, targets: Map<string, Activity>);
2140
+ activity: Activity;
2141
+ id: string | undefined;
2142
+ broker: ElementBroker<Activity>;
2122
2143
  running: Map<any, any>;
2123
- index: number;
2124
- discarded: number;
2125
2144
  watching: Map<any, any>;
2126
- targets: any;
2127
- touched: Set<any>;
2145
+ targets: Map<string, Activity>;
2128
2146
  inbound: any[];
2129
2147
  get isRunning(): boolean;
2130
- execute(executeMessage: any): number;
2131
- monitor(peerActivity: any): void;
2148
+ /**
2149
+ * Execute peer monitor
2150
+ * @returns number of running peers
2151
+ */
2152
+ execute(executeMessage: ElementBrokerMessage): number;
2153
+ /**
2154
+ * Monitor peer activity
2155
+ * */
2156
+ monitor(peerActivity: Activity): void;
2132
2157
  stop(): void;
2133
2158
  }
2134
2159
  /**