bpmn-elements 7.0.0 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/src/Context.js +50 -40
  3. package/dist/src/Environment.js +39 -19
  4. package/dist/src/MessageFormatter.js +11 -11
  5. package/dist/src/activity/Activity.js +106 -106
  6. package/dist/src/activity/ActivityExecution.js +37 -37
  7. package/dist/src/activity/Message.js +2 -2
  8. package/dist/src/activity/Signal.js +2 -2
  9. package/dist/src/definition/Definition.js +50 -50
  10. package/dist/src/definition/DefinitionExecution.js +114 -125
  11. package/dist/src/eventDefinitions/CancelEventDefinition.js +16 -16
  12. package/dist/src/eventDefinitions/CompensateEventDefinition.js +24 -24
  13. package/dist/src/eventDefinitions/ConditionalEventDefinition.js +8 -8
  14. package/dist/src/eventDefinitions/ErrorEventDefinition.js +26 -26
  15. package/dist/src/eventDefinitions/EscalationEventDefinition.js +20 -20
  16. package/dist/src/eventDefinitions/EventDefinitionExecution.js +14 -14
  17. package/dist/src/eventDefinitions/LinkEventDefinition.js +15 -15
  18. package/dist/src/eventDefinitions/MessageEventDefinition.js +23 -23
  19. package/dist/src/eventDefinitions/SignalEventDefinition.js +24 -24
  20. package/dist/src/eventDefinitions/TimerEventDefinition.js +76 -53
  21. package/dist/src/events/BoundaryEvent.js +67 -38
  22. package/dist/src/events/EndEvent.js +3 -3
  23. package/dist/src/events/IntermediateCatchEvent.js +3 -3
  24. package/dist/src/events/IntermediateThrowEvent.js +3 -3
  25. package/dist/src/events/StartEvent.js +9 -9
  26. package/dist/src/flows/Association.js +7 -7
  27. package/dist/src/flows/MessageFlow.js +9 -9
  28. package/dist/src/flows/SequenceFlow.js +7 -7
  29. package/dist/src/gateways/EventBasedGateway.js +11 -11
  30. package/dist/src/io/InputOutputSpecification.js +4 -4
  31. package/dist/src/io/Properties.js +9 -9
  32. package/dist/src/process/Process.js +64 -61
  33. package/dist/src/process/ProcessExecution.js +93 -90
  34. package/dist/src/tasks/ReceiveTask.js +16 -16
  35. package/dist/src/tasks/SubProcess.js +16 -18
  36. package/package.json +15 -16
  37. package/src/Context.js +48 -40
  38. package/src/Environment.js +48 -20
  39. package/src/EventBroker.js +1 -1
  40. package/src/MessageFormatter.js +11 -11
  41. package/src/activity/Activity.js +99 -100
  42. package/src/activity/ActivityExecution.js +35 -35
  43. package/src/activity/Message.js +1 -1
  44. package/src/activity/Signal.js +1 -1
  45. package/src/definition/Definition.js +51 -50
  46. package/src/definition/DefinitionExecution.js +111 -113
  47. package/src/eventDefinitions/CancelEventDefinition.js +16 -16
  48. package/src/eventDefinitions/CompensateEventDefinition.js +25 -24
  49. package/src/eventDefinitions/ConditionalEventDefinition.js +8 -8
  50. package/src/eventDefinitions/ErrorEventDefinition.js +26 -26
  51. package/src/eventDefinitions/EscalationEventDefinition.js +20 -20
  52. package/src/eventDefinitions/EventDefinitionExecution.js +14 -14
  53. package/src/eventDefinitions/LinkEventDefinition.js +15 -15
  54. package/src/eventDefinitions/MessageEventDefinition.js +23 -23
  55. package/src/eventDefinitions/SignalEventDefinition.js +24 -24
  56. package/src/eventDefinitions/TimerEventDefinition.js +61 -44
  57. package/src/events/BoundaryEvent.js +53 -36
  58. package/src/events/EndEvent.js +3 -3
  59. package/src/events/IntermediateCatchEvent.js +3 -3
  60. package/src/events/IntermediateThrowEvent.js +3 -3
  61. package/src/events/StartEvent.js +9 -9
  62. package/src/flows/Association.js +7 -7
  63. package/src/flows/MessageFlow.js +9 -9
  64. package/src/flows/SequenceFlow.js +7 -7
  65. package/src/gateways/EventBasedGateway.js +11 -11
  66. package/src/io/BpmnIO.js +5 -1
  67. package/src/io/InputOutputSpecification.js +4 -4
  68. package/src/io/Properties.js +9 -9
  69. package/src/process/Process.js +62 -58
  70. package/src/process/ProcessExecution.js +86 -88
  71. package/src/tasks/ReceiveTask.js +16 -16
  72. package/src/tasks/SubProcess.js +16 -16
@@ -2,11 +2,11 @@ import getPropertyValue from '../getPropertyValue';
2
2
  import {brokerSafeId} from '../shared';
3
3
  import {cloneContent, shiftParent} from '../messageHelper';
4
4
 
5
- const completedSymbol = Symbol.for('completed');
6
- const messageQSymbol = Symbol.for('messageQ');
7
- const executeMessageSymbol = Symbol.for('executeMessage');
8
- const referenceElementSymbol = Symbol.for('referenceElement');
9
- const referenceInfoSymbol = Symbol.for('referenceInfo');
5
+ const kCompleted = Symbol.for('completed');
6
+ const kMessageQ = Symbol.for('messageQ');
7
+ const kExecuteMessage = Symbol.for('executeMessage');
8
+ const kReferenceElement = Symbol.for('referenceElement');
9
+ const kReferenceInfo = Symbol.for('referenceInfo');
10
10
 
11
11
  export default function MessageEventDefinition(activity, eventDefinition) {
12
12
  const {id, broker, environment, isThrowing} = activity;
@@ -26,12 +26,12 @@ export default function MessageEventDefinition(activity, eventDefinition) {
26
26
  this.broker = broker;
27
27
  this.logger = environment.Logger(type.toLowerCase());
28
28
 
29
- const referenceElement = this[referenceElementSymbol] = reference.id && activity.getActivityById(reference.id);
29
+ const referenceElement = this[kReferenceElement] = reference.id && activity.getActivityById(reference.id);
30
30
  if (!isThrowing) {
31
- this[completedSymbol] = false;
31
+ this[kCompleted] = false;
32
32
  const referenceId = referenceElement ? referenceElement.id : 'anonymous';
33
33
  const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`;
34
- this[messageQSymbol] = broker.assertQueue(messageQueueName, {autoDelete: false, durable: true});
34
+ this[kMessageQ] = broker.assertQueue(messageQueueName, {autoDelete: false, durable: true});
35
35
  broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, {durable: true});
36
36
  }
37
37
  }
@@ -40,7 +40,7 @@ const proto = MessageEventDefinition.prototype;
40
40
 
41
41
  Object.defineProperty(proto, 'executionId', {
42
42
  get() {
43
- const message = this[executeMessageSymbol];
43
+ const message = this[kExecuteMessage];
44
44
  return message && message.content.executionId;
45
45
  },
46
46
  });
@@ -50,24 +50,24 @@ proto.execute = function execute(executeMessage) {
50
50
  };
51
51
 
52
52
  proto.executeCatch = function executeCatch(executeMessage) {
53
- this[executeMessageSymbol] = executeMessage;
54
- this[completedSymbol] = false;
53
+ this[kExecuteMessage] = executeMessage;
54
+ this[kCompleted] = false;
55
55
 
56
56
  const executeContent = executeMessage.content;
57
57
  const {executionId, parent} = executeContent;
58
58
  const parentExecutionId = parent && parent.executionId;
59
59
 
60
- const info = this[referenceInfoSymbol] = this._getReferenceInfo(executeMessage);
60
+ const info = this[kReferenceInfo] = this._getReferenceInfo(executeMessage);
61
61
  this._debug(`expect ${info.description}`);
62
62
 
63
63
  const broker = this.broker;
64
64
  const onCatchMessage = this._onCatchMessage.bind(this);
65
- this[messageQSymbol].consume(onCatchMessage, {
65
+ this[kMessageQ].consume(onCatchMessage, {
66
66
  noAck: true,
67
67
  consumerTag: `_api-message-${executionId}`,
68
68
  });
69
69
 
70
- if (this[completedSymbol]) return;
70
+ if (this[kCompleted]) return;
71
71
 
72
72
  const onApiMessage = this._onApiMessage.bind(this);
73
73
  broker.subscribeTmp('api', `activity.#.${executionId}`, onApiMessage, {
@@ -115,10 +115,10 @@ proto.executeThrow = function executeThrow(executeMessage) {
115
115
  };
116
116
 
117
117
  proto._onCatchMessage = function onCatchMessage(routingKey, message) {
118
- if (getPropertyValue(message, 'content.message.id') !== this[referenceInfoSymbol].message.id) return;
118
+ if (getPropertyValue(message, 'content.message.id') !== this[kReferenceInfo].message.id) return;
119
119
 
120
120
  const {type, correlationId} = message.properties;
121
- this.broker.publish('event', 'activity.consumed', cloneContent(this[executeMessageSymbol].content, {
121
+ this.broker.publish('event', 'activity.consumed', cloneContent(this[kExecuteMessage].content, {
122
122
  message: {...message.content.message},
123
123
  }), {
124
124
  correlationId,
@@ -136,9 +136,9 @@ proto._onApiMessage = function onApiMessage(routingKey, message) {
136
136
  return this._complete('got signal with', message.content.message, {correlationId});
137
137
  }
138
138
  case 'discard': {
139
- this[completedSymbol] = true;
139
+ this[kCompleted] = true;
140
140
  this._stop();
141
- return this.broker.publish('execution', 'execute.discard', cloneContent(this[executeMessageSymbol].content), {correlationId});
141
+ return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content), {correlationId});
142
142
  }
143
143
  case 'stop': {
144
144
  return this._stop();
@@ -147,13 +147,13 @@ proto._onApiMessage = function onApiMessage(routingKey, message) {
147
147
  };
148
148
 
149
149
  proto._complete = function complete(verb, output, options) {
150
- this[completedSymbol] = true;
150
+ this[kCompleted] = true;
151
151
 
152
152
  this._stop();
153
- this._debug(`${verb} ${this[referenceInfoSymbol].description}`);
153
+ this._debug(`${verb} ${this[kReferenceInfo].description}`);
154
154
 
155
155
  const broker = this.broker;
156
- const executeContent = this[executeMessageSymbol].content;
156
+ const executeContent = this[kExecuteMessage].content;
157
157
  const catchContent = cloneContent(executeContent, {
158
158
  message: {...output},
159
159
  executionId: executeContent.parent.executionId,
@@ -174,11 +174,11 @@ proto._stop = function stop() {
174
174
  broker.cancel(`_api-${executionId}`);
175
175
  broker.cancel(`_api-parent-${executionId}`);
176
176
  broker.cancel(`_api-delegated-${executionId}`);
177
- this[messageQSymbol].purge();
177
+ this[kMessageQ].purge();
178
178
  };
179
179
 
180
180
  proto._getReferenceInfo = function getReferenceInfo(message) {
181
- const referenceElement = this[referenceElementSymbol];
181
+ const referenceElement = this[kReferenceElement];
182
182
  if (!referenceElement) {
183
183
  return {
184
184
  message: {...this.reference},
@@ -2,11 +2,11 @@ import getPropertyValue from '../getPropertyValue';
2
2
  import {brokerSafeId} from '../shared';
3
3
  import {cloneContent, shiftParent} from '../messageHelper';
4
4
 
5
- const completedSymbol = Symbol.for('completed');
6
- const messageQSymbol = Symbol.for('messageQ');
7
- const executeMessageSymbol = Symbol.for('executeMessage');
8
- const referenceElementSymbol = Symbol.for('referenceElement');
9
- const referenceInfoSymbol = Symbol.for('referenceInfo');
5
+ const kCompleted = Symbol.for('completed');
6
+ const kMessageQ = Symbol.for('messageQ');
7
+ const kExecuteMessage = Symbol.for('executeMessage');
8
+ const kReferenceElement = Symbol.for('referenceElement');
9
+ const kReferenceInfo = Symbol.for('referenceInfo');
10
10
 
11
11
  export default function SignalEventDefinition(activity, eventDefinition) {
12
12
  const {id, broker, environment, isStart, isThrowing} = activity;
@@ -26,12 +26,12 @@ export default function SignalEventDefinition(activity, eventDefinition) {
26
26
  this.broker = broker;
27
27
  this.logger = environment.Logger(type.toLowerCase());
28
28
 
29
- const referenceElement = this[referenceElementSymbol] = reference.id && activity.getActivityById(reference.id);
29
+ const referenceElement = this[kReferenceElement] = reference.id && activity.getActivityById(reference.id);
30
30
  if (!isThrowing && isStart) {
31
- this[completedSymbol] = false;
31
+ this[kCompleted] = false;
32
32
  const referenceId = referenceElement ? referenceElement.id : 'anonymous';
33
33
  const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-${brokerSafeId(referenceId)}-q`;
34
- this[messageQSymbol] = broker.assertQueue(messageQueueName, {autoDelete: false, durable: true});
34
+ this[kMessageQ] = broker.assertQueue(messageQueueName, {autoDelete: false, durable: true});
35
35
  broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, {durable: true});
36
36
  }
37
37
  }
@@ -40,7 +40,7 @@ const proto = SignalEventDefinition.prototype;
40
40
 
41
41
  Object.defineProperty(proto, 'executionId', {
42
42
  get() {
43
- const message = this[executeMessageSymbol];
43
+ const message = this[kExecuteMessage];
44
44
  return message && message.content.executionId;
45
45
  },
46
46
  });
@@ -50,23 +50,23 @@ proto.execute = function execute(executeMessage) {
50
50
  };
51
51
 
52
52
  proto.executeCatch = function executeCatch(executeMessage) {
53
- this[executeMessageSymbol] = executeMessage;
54
- this[completedSymbol] = false;
53
+ this[kExecuteMessage] = executeMessage;
54
+ this[kCompleted] = false;
55
55
 
56
56
  const executeContent = executeMessage.content;
57
57
  const {executionId, parent} = executeContent;
58
58
  const parentExecutionId = parent && parent.executionId;
59
59
 
60
- const info = this[referenceInfoSymbol] = this._getReferenceInfo(executeMessage);
60
+ const info = this[kReferenceInfo] = this._getReferenceInfo(executeMessage);
61
61
  const broker = this.broker;
62
62
 
63
63
  const onCatchMessage = this._onCatchMessage.bind(this);
64
64
  if (this.activity.isStart) {
65
- this[messageQSymbol].consume(onCatchMessage, {
65
+ this[kMessageQ].consume(onCatchMessage, {
66
66
  noAck: true,
67
67
  consumerTag: `_api-signal-${executionId}`,
68
68
  });
69
- if (this[completedSymbol]) return;
69
+ if (this[kCompleted]) return;
70
70
  }
71
71
 
72
72
  const onApiMessage = this._onApiMessage.bind(this);
@@ -116,13 +116,13 @@ proto.executeThrow = function executeThrow(executeMessage) {
116
116
  };
117
117
 
118
118
  proto._onCatchMessage = function onCatchMessage(routingKey, message) {
119
- const info = this[referenceInfoSymbol];
119
+ const info = this[kReferenceInfo];
120
120
  if (getPropertyValue(message, 'content.message.id') !== info.message.id) return;
121
- this[completedSymbol] = true;
121
+ this[kCompleted] = true;
122
122
  this._stop();
123
123
 
124
124
  const {type, correlationId} = message.properties;
125
- this.broker.publish('event', 'activity.consumed', cloneContent(this[executeMessageSymbol].content, {
125
+ this.broker.publish('event', 'activity.consumed', cloneContent(this[kExecuteMessage].content, {
126
126
  message: { ...message.content.message},
127
127
  }), {
128
128
  correlationId,
@@ -140,9 +140,9 @@ proto._onApiMessage = function onApiMessage(routingKey, message) {
140
140
  return this._complete(message.content.message, {correlationId});
141
141
  }
142
142
  case 'discard': {
143
- this[completedSymbol] = true;
143
+ this[kCompleted] = true;
144
144
  this._stop();
145
- return this.broker.publish('execution', 'execute.discard', cloneContent(this[executeMessageSymbol].content), {correlationId});
145
+ return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content), {correlationId});
146
146
  }
147
147
  case 'stop': {
148
148
  this._stop();
@@ -152,10 +152,10 @@ proto._onApiMessage = function onApiMessage(routingKey, message) {
152
152
  };
153
153
 
154
154
  proto._complete = function complete(output, options) {
155
- this[completedSymbol] = true;
155
+ this[kCompleted] = true;
156
156
  this._stop();
157
- this._debug(`signaled with ${this[referenceInfoSymbol].description}`);
158
- return this.broker.publish('execution', 'execute.completed', cloneContent(this[executeMessageSymbol].content, {
157
+ this._debug(`signaled with ${this[kReferenceInfo].description}`);
158
+ return this.broker.publish('execution', 'execute.completed', cloneContent(this[kExecuteMessage].content, {
159
159
  output,
160
160
  state: 'signal',
161
161
  }), options);
@@ -167,11 +167,11 @@ proto._stop = function stop() {
167
167
  broker.cancel(`_api-parent-${executionId}`);
168
168
  broker.cancel(`_api-${executionId}`);
169
169
  broker.cancel(`_api-delegated-${executionId}`);
170
- if (this.activity.isStart) this[messageQSymbol].purge();
170
+ if (this.activity.isStart) this[kMessageQ].purge();
171
171
  };
172
172
 
173
173
  proto._getReferenceInfo = function getReferenceInfo(message) {
174
- const referenceElement = this[referenceElementSymbol];
174
+ const referenceElement = this[kReferenceElement];
175
175
  if (!referenceElement) {
176
176
  return {
177
177
  message: {...this.reference},
@@ -1,9 +1,10 @@
1
1
  import {cloneContent} from '../messageHelper';
2
2
  import {toSeconds, parse} from 'iso8601-duration';
3
3
 
4
- const stoppedSymbol = Symbol.for('stopped');
5
- const timerContentSymbol = Symbol.for('timerContent');
6
- const timerSymbol = Symbol.for('timer');
4
+ const kStopped = Symbol.for('stopped');
5
+ const kTimerContent = Symbol.for('timerContent');
6
+ const kTimer = Symbol.for('timer');
7
+ const repeatPattern = /^\s*R(\d+)\//;
7
8
 
8
9
  export default function TimerEventDefinition(activity, eventDefinition) {
9
10
  const type = this.type = eventDefinition.type || 'TimerEventDefinition';
@@ -19,15 +20,15 @@ export default function TimerEventDefinition(activity, eventDefinition) {
19
20
  this.broker = activity.broker;
20
21
  this.logger = environment.Logger(type.toLowerCase());
21
22
 
22
- this[stoppedSymbol] = false;
23
- this[timerSymbol] = null;
23
+ this[kStopped] = false;
24
+ this[kTimer] = null;
24
25
  }
25
26
 
26
27
  const proto = TimerEventDefinition.prototype;
27
28
 
28
29
  Object.defineProperty(proto, 'executionId', {
29
30
  get() {
30
- const content = this[timerContentSymbol];
31
+ const content = this[kTimerContent];
31
32
  return content && content.executionId;
32
33
  },
33
34
  });
@@ -35,35 +36,35 @@ Object.defineProperty(proto, 'executionId', {
35
36
  Object.defineProperty(proto, 'stopped', {
36
37
  enumerable: true,
37
38
  get() {
38
- return this[stoppedSymbol];
39
+ return this[kStopped];
39
40
  },
40
41
  });
41
42
 
42
43
  Object.defineProperty(proto, 'timer', {
43
44
  enumerable: true,
44
45
  get() {
45
- return this[timerSymbol];
46
+ return this[kTimer];
46
47
  },
47
48
  });
48
49
 
49
50
  proto.execute = function execute(executeMessage) {
50
51
  const {routingKey: executeKey, redelivered: isResumed} = executeMessage.fields;
51
- const timer = this[timerSymbol];
52
+ const timer = this[kTimer];
52
53
  if (timer && executeKey === 'execute.timer') {
53
54
  return;
54
55
  }
55
56
 
56
- if (timer) this[timerSymbol] = this.environment.timers.clearTimeout(timer);
57
- this[stoppedSymbol] = false;
57
+ if (timer) this[kTimer] = this.environment.timers.clearTimeout(timer);
58
+ this[kStopped] = false;
58
59
 
59
60
  const content = executeMessage.content;
60
61
  const executionId = content.executionId;
61
62
  const startedAt = this.startedAt = 'startedAt' in content ? new Date(content.startedAt) : new Date();
62
63
 
63
64
  const resolvedTimer = this._getTimers(executeMessage);
64
- const timerContent = this[timerContentSymbol] = cloneContent(content, {
65
+ const timerContent = this[kTimerContent] = cloneContent(content, {
65
66
  ...resolvedTimer,
66
- ...(isResumed ? {isResumed} : undefined),
67
+ ...(isResumed && {isResumed}),
67
68
  startedAt,
68
69
  state: 'timer',
69
70
  });
@@ -86,7 +87,7 @@ proto.execute = function execute(executeMessage) {
86
87
  if (timerContent.timeout <= 0) return this._completed();
87
88
 
88
89
  const timers = this.environment.timers.register(timerContent);
89
- this[timerSymbol] = timers.setTimeout(this._completed.bind(this), timerContent.timeout, {
90
+ this[kTimer] = timers.setTimeout(this._completed.bind(this), timerContent.timeout, {
90
91
  id: content.id,
91
92
  type: this.type,
92
93
  executionId,
@@ -95,8 +96,8 @@ proto.execute = function execute(executeMessage) {
95
96
  };
96
97
 
97
98
  proto.stop = function stopTimer() {
98
- const timer = this[timerSymbol];
99
- if (timer) this[timerSymbol] = this.environment.timers.clearTimeout(timer);
99
+ const timer = this[kTimer];
100
+ if (timer) this[kTimer] = this.environment.timers.clearTimeout(timer);
100
101
  };
101
102
 
102
103
  proto._completed = function completed(completeContent, options) {
@@ -107,11 +108,17 @@ proto._completed = function completed(completeContent, options) {
107
108
  const runningTime = stoppedAt.getTime() - this.startedAt.getTime();
108
109
  this._debug(`completed in ${runningTime}ms`);
109
110
 
110
- const timerContent = this[timerContentSymbol];
111
+ const timerContent = this[kTimerContent];
111
112
  const content = {stoppedAt, runningTime, state: 'timeout', ...completeContent};
112
113
 
113
114
  const broker = this.broker;
114
115
  broker.publish('event', 'activity.timeout', cloneContent(timerContent, content), options);
116
+
117
+ if (timerContent.repeat > 1) {
118
+ const repeat = timerContent.repeat - 1;
119
+ broker.publish('execution', 'execute.repeat', cloneContent(timerContent, {...content, repeat}), options);
120
+ }
121
+
115
122
  broker.publish('execution', 'execute.completed', cloneContent(timerContent, content), options);
116
123
  };
117
124
 
@@ -129,7 +136,7 @@ proto._onDelegatedApiMessage = function onDelegatedApiMessage(routingKey, messag
129
136
  if (signalExecutionId && signalId === id && signalExecutionId !== executionId) return;
130
137
 
131
138
  const {type, correlationId} = message.properties;
132
- this.broker.publish('event', 'activity.consumed', cloneContent(this[timerContentSymbol], {
139
+ this.broker.publish('event', 'activity.consumed', cloneContent(this[kTimerContent], {
133
140
  message: {
134
141
  ...content.message,
135
142
  },
@@ -146,7 +153,7 @@ proto._onApiMessage = function onApiMessage(routingKey, message) {
146
153
  this._stop();
147
154
  return this._completed({
148
155
  state: 'cancel',
149
- ...(message.content.message ? {message: message.content.message} : undefined),
156
+ ...(message.content.message && {message: message.content.message}),
150
157
  }, {correlationId});
151
158
  }
152
159
  case 'stop': {
@@ -156,15 +163,15 @@ proto._onApiMessage = function onApiMessage(routingKey, message) {
156
163
  case 'discard': {
157
164
  this._stop();
158
165
  this._debug('discarded');
159
- return this.broker.publish('execution', 'execute.discard', cloneContent(this[timerContentSymbol], {state: 'discard'}), {correlationId});
166
+ return this.broker.publish('execution', 'execute.discard', cloneContent(this[kTimerContent], {state: 'discard'}), {correlationId});
160
167
  }
161
168
  }
162
169
  };
163
170
 
164
171
  proto._stop = function stop() {
165
- this[stoppedSymbol] = true;
166
- const timer = this[timerSymbol];
167
- if (timer) this[timerSymbol] = this.environment.timers.clearTimeout(timer);
172
+ this[kStopped] = true;
173
+ const timer = this[kTimer];
174
+ if (timer) this[kTimer] = this.environment.timers.clearTimeout(timer);
168
175
  const broker = this.broker;
169
176
  broker.cancel(`_api-${this.executionId}`);
170
177
  broker.cancel(`_api-delegated-${this.executionId}`);
@@ -175,7 +182,7 @@ proto._getTimers = function getTimers(executeMessage) {
175
182
 
176
183
  const now = Date.now();
177
184
  const result = {
178
- ...('expireAt' in content ? {expireAt: new Date(content.expireAt)} : undefined),
185
+ ...('expireAt' in content && {expireAt: new Date(content.expireAt)}),
179
186
  };
180
187
 
181
188
  for (const t of ['timeDuration', 'timeDate', 'timeCycle']) {
@@ -183,33 +190,39 @@ proto._getTimers = function getTimers(executeMessage) {
183
190
  else if (t in this) result[t] = this.environment.resolveExpression(this[t], executeMessage);
184
191
  else continue;
185
192
 
186
- let expireAtDate;
187
- if (t === 'timeDuration') {
188
- const durationStr = result[t];
189
- if (durationStr) {
190
- const delay = this._getDurationInMilliseconds(durationStr);
191
- if (delay !== undefined) expireAtDate = new Date(now + delay);
192
- } else {
193
- expireAtDate = new Date(now);
194
- }
195
- } else if (t === 'timeDate') {
196
- const dateStr = result[t];
197
- if (dateStr) {
198
- const ms = Date.parse(dateStr);
199
- if (!isNaN(ms)) {
200
- expireAtDate = new Date(ms);
201
- } else {
202
- this._warn(`invalid timeDate >${dateStr}<`);
193
+ let expireAtDate, repeat;
194
+ const timerStr = result[t];
195
+ if (timerStr) {
196
+ switch (t) {
197
+ case 'timeCycle': {
198
+ const mRepeat = timerStr.match(repeatPattern);
199
+ if (mRepeat && mRepeat.length) repeat = parseInt(mRepeat[1]);
200
+ }
201
+ case 'timeDuration': {
202
+ const delay = this._getDurationInMilliseconds(timerStr);
203
+ if (delay !== undefined) expireAtDate = new Date(now + delay);
204
+ break;
205
+ }
206
+ case 'timeDate': {
207
+ const dateStr = result[t];
208
+ const ms = Date.parse(dateStr);
209
+ if (!isNaN(ms)) {
210
+ expireAtDate = new Date(ms);
211
+ } else {
212
+ this._warn(`invalid timeDate >${dateStr}<`);
213
+ }
214
+ break;
203
215
  }
204
- } else {
205
- expireAtDate = new Date(now);
206
216
  }
217
+ } else {
218
+ expireAtDate = new Date(now);
207
219
  }
208
220
 
209
221
  if (!expireAtDate) continue;
210
222
  if (!('expireAt' in result) || result.expireAt > expireAtDate) {
211
223
  result.timerType = t;
212
224
  result.expireAt = expireAtDate;
225
+ if (repeat) result.repeat = repeat;
213
226
  }
214
227
  }
215
228
 
@@ -221,6 +234,10 @@ proto._getTimers = function getTimers(executeMessage) {
221
234
  result.timeout = 0;
222
235
  }
223
236
 
237
+ if (content.inbound && 'repeat' in content.inbound[0]) {
238
+ result.repeat = content.inbound[0].repeat;
239
+ }
240
+
224
241
  return result;
225
242
  };
226
243
 
@@ -228,7 +245,7 @@ proto._getDurationInMilliseconds = function getDurationInMilliseconds(duration)
228
245
  try {
229
246
  return toSeconds(parse(duration)) * 1000;
230
247
  } catch (err) {
231
- this._warn(`failed to parse timeDuration >${duration}<: ${err.message}`);
248
+ this._warn(`failed to parse ${this.timerType} >${duration}<: ${err.message}`);
232
249
  }
233
250
  };
234
251
 
@@ -3,11 +3,11 @@ import EventDefinitionExecution from '../eventDefinitions/EventDefinitionExecuti
3
3
  import {cloneContent, cloneMessage} from '../messageHelper';
4
4
  import {brokerSafeId} from '../shared';
5
5
 
6
- const attachedTagsSymbol = Symbol.for('attachedConsumers');
7
- const completeContentSymbol = Symbol.for('completeContent');
8
- const executeMessageSymbol = Symbol.for('executeMessage');
9
- const executionSymbol = Symbol.for('execution');
10
- const shovelsSymbol = Symbol.for('shovels');
6
+ const kAttachedTags = Symbol.for('attachedConsumers');
7
+ const kCompleteContent = Symbol.for('completeContent');
8
+ const kExecuteMessage = Symbol.for('executeMessage');
9
+ const kExecution = Symbol.for('execution');
10
+ const kShovels = Symbol.for('shovels');
11
11
 
12
12
  export default function BoundaryEvent(activityDef, context) {
13
13
  return new Activity(BoundaryEventBehaviour, activityDef, context);
@@ -20,16 +20,16 @@ export function BoundaryEventBehaviour(activity) {
20
20
  this.activity = activity;
21
21
  this.environment = activity.environment;
22
22
  this.broker = activity.broker;
23
- this[executionSymbol] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions, 'execute.bound.completed');
24
- this[shovelsSymbol] = [];
25
- this[attachedTagsSymbol] = [];
23
+ this[kExecution] = activity.eventDefinitions && new EventDefinitionExecution(activity, activity.eventDefinitions, 'execute.bound.completed');
24
+ this[kShovels] = [];
25
+ this[kAttachedTags] = [];
26
26
  }
27
27
 
28
28
  const proto = BoundaryEventBehaviour.prototype;
29
29
 
30
30
  Object.defineProperty(proto, 'executionId', {
31
31
  get() {
32
- const message = this[executeMessageSymbol];
32
+ const message = this[kExecuteMessage];
33
33
  return message && message.content.executionId;
34
34
  },
35
35
  });
@@ -45,35 +45,32 @@ Object.defineProperty(proto, 'cancelActivity', {
45
45
  proto.execute = function execute(executeMessage) {
46
46
  const {isRootScope, executionId} = executeMessage.content;
47
47
 
48
- const eventDefinitionExecution = this[executionSymbol];
48
+ const eventDefinitionExecution = this[kExecution];
49
49
  if (isRootScope) {
50
- this[executeMessageSymbol] = executeMessage;
50
+ this[kExecuteMessage] = executeMessage;
51
51
 
52
52
  const broker = this.broker;
53
- if (eventDefinitionExecution && !this.environment.settings.strict) {
54
- broker.subscribeTmp('execution', 'execute.expect', this._onExpectMessage.bind(this), {
55
- noAck: true,
56
- consumerTag: '_expect-tag',
57
- });
58
- }
59
-
60
53
  const consumerTag = `_bound-listener-${executionId}`;
61
54
  this.attachedTo.broker.subscribeTmp('event', 'activity.leave', this._onAttachedLeave.bind(this), {
62
55
  noAck: true,
63
56
  consumerTag,
64
57
  priority: 300,
65
58
  });
66
- this[attachedTagsSymbol].push(consumerTag);
59
+ this[kAttachedTags].push(consumerTag);
67
60
 
68
- broker.subscribeOnce('execution', 'execute.detach', this._onDetachMessage.bind(this), {
69
- consumerTag: '_detach-tag',
70
- });
71
61
  broker.subscribeOnce('api', `activity.#.${executionId}`, this._onApiMessage.bind(this), {
72
62
  consumerTag: `_api-${executionId}`,
73
63
  });
74
- broker.subscribeOnce('execution', 'execute.bound.completed', this._onCompleted.bind(this), {
75
- consumerTag: `_execution-completed-${executionId}`,
76
- });
64
+
65
+ const execQ = broker.assertQueue(`_bound-execution-${executionId}`, {durable: false, autoDelete: true});
66
+ broker.bindQueue(execQ.name, 'execution', 'execute.detach');
67
+ broker.bindQueue(execQ.name, 'execution', 'execute.bound.completed');
68
+ broker.bindQueue(execQ.name, 'execution', 'execute.repeat');
69
+ if (eventDefinitionExecution && !this.environment.settings.strict) {
70
+ broker.bindQueue(execQ.name, 'execution', 'execute.expect');
71
+ }
72
+
73
+ execQ.consume(this._onExecutionMessage.bind(this), {consumerTag: '_execution-tag'});
77
74
  }
78
75
 
79
76
  if (eventDefinitionExecution) {
@@ -81,15 +78,29 @@ proto.execute = function execute(executeMessage) {
81
78
  }
82
79
  };
83
80
 
81
+ proto._onExecutionMessage = function onExecutionMessage(routingKey, message) {
82
+ message.ack();
83
+ switch (routingKey) {
84
+ case 'execute.detach':
85
+ return this._onDetachMessage(routingKey, message);
86
+ case 'execute.bound.completed':
87
+ return this._onCompleted(routingKey, message);
88
+ case 'execute.repeat':
89
+ return this._onRepeatMessage(routingKey, message);
90
+ case 'execute.expect':
91
+ return this._onExpectMessage(routingKey, message);
92
+ }
93
+ };
94
+
84
95
  proto._onCompleted = function onCompleted(_, {content}) {
85
96
  if (!this.cancelActivity && !content.cancelActivity) {
86
97
  this._stop();
87
- return this.broker.publish('execution', 'execute.completed', cloneContent(content));
98
+ return this.broker.publish('execution', 'execute.completed', cloneContent(content, {cancelActivity: false}));
88
99
  }
89
100
 
90
- this[completeContentSymbol] = content;
101
+ this[kCompleteContent] = content;
91
102
 
92
- const {inbound} = this[executeMessageSymbol].content;
103
+ const inbound = this[kExecuteMessage].content.inbound;
93
104
  const attachedToContent = inbound && inbound[0];
94
105
  const attachedTo = this.attachedTo;
95
106
  this.activity.logger.debug(`<${this.executionId} (${this.id})> cancel ${attachedTo.status} activity <${attachedToContent.executionId} (${attachedToContent.id})>`);
@@ -100,8 +111,8 @@ proto._onCompleted = function onCompleted(_, {content}) {
100
111
  proto._onAttachedLeave = function onAttachedLeave(_, {content}) {
101
112
  if (content.id !== this.attachedTo.id) return;
102
113
  this._stop();
103
- const completeContent = this[completeContentSymbol];
104
- if (!completeContent) return this.broker.publish('execution', 'execute.discard', this[executeMessageSymbol].content);
114
+ const completeContent = this[kCompleteContent];
115
+ if (!completeContent) return this.broker.publish('execution', 'execute.discard', this[kExecuteMessage].content);
105
116
  return this.broker.publish('execution', 'execute.completed', cloneContent(completeContent));
106
117
  };
107
118
 
@@ -110,7 +121,7 @@ proto._onExpectMessage = function onExpectMessage(_, {content}) {
110
121
  const attachedTo = this.attachedTo;
111
122
 
112
123
  const errorConsumerTag = `_bound-error-listener-${executionId}`;
113
- this[attachedTagsSymbol].push(errorConsumerTag);
124
+ this[kAttachedTags].push(errorConsumerTag);
114
125
 
115
126
  attachedTo.broker.subscribeTmp('event', 'activity.error', (__, errorMessage) => {
116
127
  if (errorMessage.content.id !== attachedTo.id) return;
@@ -130,7 +141,7 @@ proto._onDetachMessage = function onDetachMessage(_, {content}) {
130
141
  const {executionId: detachId, bindExchange, sourceExchange, sourcePattern} = content;
131
142
 
132
143
  const shovelName = `_detached-${brokerSafeId(id)}_${detachId}`;
133
- this[shovelsSymbol].push(shovelName);
144
+ this[kShovels].push(shovelName);
134
145
 
135
146
  const broker = this.broker;
136
147
  attachedTo.broker.createShovel(shovelName, {
@@ -160,13 +171,19 @@ proto._onApiMessage = function onApiMessage(_, message) {
160
171
  }
161
172
  };
162
173
 
174
+ proto._onRepeatMessage = function onRepeatMessage(_, message) {
175
+ if (this.cancelActivity) return;
176
+ const executeMessage = this[kExecuteMessage];
177
+ const repeat = message.content.repeat;
178
+ this.broker.getQueue('inbound-q').queueMessage({routingKey: 'activity.restart'}, cloneContent(executeMessage.content.inbound[0], {repeat}));
179
+ };
180
+
163
181
  proto._stop = function stop(detach) {
164
182
  const attachedTo = this.attachedTo, broker = this.broker, executionId = this.executionId;
165
- for (const tag of this[attachedTagsSymbol].splice(0)) attachedTo.broker.cancel(tag);
166
- for (const shovelName of this[shovelsSymbol].splice(0)) attachedTo.broker.closeShovel(shovelName);
183
+ for (const tag of this[kAttachedTags].splice(0)) attachedTo.broker.cancel(tag);
184
+ for (const shovelName of this[kShovels].splice(0)) attachedTo.broker.closeShovel(shovelName);
167
185
 
168
- broker.cancel('_expect-tag');
169
- broker.cancel('_detach-tag');
186
+ broker.cancel('_execution-tag');
170
187
  broker.cancel(`_execution-completed-${executionId}`);
171
188
 
172
189
  if (detach) return;