bpmn-elements 9.0.0 → 9.1.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.
- package/CHANGELOG.md +11 -0
- package/README.md +1 -1
- package/dist/EventBroker.js +4 -0
- package/dist/Tracker.js +89 -0
- package/dist/activity/Activity.js +47 -57
- package/dist/activity/ActivityExecution.js +6 -9
- package/dist/definition/Definition.js +23 -17
- package/dist/definition/DefinitionExecution.js +23 -0
- package/dist/eventDefinitions/CancelEventDefinition.js +20 -76
- package/dist/eventDefinitions/CompensateEventDefinition.js +54 -41
- package/dist/eventDefinitions/ConditionalEventDefinition.js +11 -2
- package/dist/eventDefinitions/ErrorEventDefinition.js +2 -0
- package/dist/events/BoundaryEvent.js +25 -10
- package/dist/flows/Association.js +0 -7
- package/dist/gateways/EventBasedGateway.js +1 -2
- package/dist/process/Process.js +5 -0
- package/dist/process/ProcessExecution.js +128 -36
- package/dist/tasks/SubProcess.js +2 -1
- package/package.json +5 -5
- package/src/EventBroker.js +1 -0
- package/src/Tracker.js +73 -0
- package/src/activity/Activity.js +45 -51
- package/src/activity/ActivityExecution.js +6 -8
- package/src/definition/Definition.js +24 -21
- package/src/definition/DefinitionExecution.js +26 -0
- package/src/eventDefinitions/CancelEventDefinition.js +22 -66
- package/src/eventDefinitions/CompensateEventDefinition.js +48 -40
- package/src/eventDefinitions/ConditionalEventDefinition.js +12 -2
- package/src/eventDefinitions/ErrorEventDefinition.js +2 -0
- package/src/events/BoundaryEvent.js +20 -8
- package/src/flows/Association.js +0 -10
- package/src/gateways/EventBasedGateway.js +1 -2
- package/src/process/Process.js +6 -0
- package/src/process/ProcessExecution.js +126 -36
- package/src/tasks/SubProcess.js +2 -1
- package/types/index.d.ts +132 -11
|
@@ -20,9 +20,10 @@ export default function CompensateEventDefinition(activity, eventDefinition, con
|
|
|
20
20
|
|
|
21
21
|
if (!isThrowing) {
|
|
22
22
|
this[kCompleted] = false;
|
|
23
|
-
this[kAssociations] = context.getOutboundAssociations(id)
|
|
23
|
+
this[kAssociations] = context.getOutboundAssociations(id);
|
|
24
24
|
const messageQueueName = `${reference.referenceType}-${brokerSafeId(id)}-q`;
|
|
25
25
|
this[kMessageQ] = broker.assertQueue(messageQueueName, {autoDelete: false, durable: true});
|
|
26
|
+
this[kCompensateQ] = broker.assertQueue('compensate-q', {autoDelete: false, durable: true});
|
|
26
27
|
broker.bindQueue(messageQueueName, 'api', `*.${reference.referenceType}.#`, {durable: true, priority: 400});
|
|
27
28
|
}
|
|
28
29
|
}
|
|
@@ -41,6 +42,11 @@ CompensateEventDefinition.prototype.execute = function execute(executeMessage) {
|
|
|
41
42
|
CompensateEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) {
|
|
42
43
|
this[kExecuteMessage] = executeMessage;
|
|
43
44
|
this[kCompleted] = false;
|
|
45
|
+
if (executeMessage.fields.routingKey === 'execute.compensating') {
|
|
46
|
+
this._debug('resumed at compensating');
|
|
47
|
+
this[kCompleted] = true;
|
|
48
|
+
return this._compensate();
|
|
49
|
+
}
|
|
44
50
|
|
|
45
51
|
const executeContent = executeMessage.content;
|
|
46
52
|
const {executionId, parent} = executeContent;
|
|
@@ -48,18 +54,13 @@ CompensateEventDefinition.prototype.executeCatch = function executeCatch(execute
|
|
|
48
54
|
this._debug('expect compensate');
|
|
49
55
|
|
|
50
56
|
const broker = this.broker;
|
|
57
|
+
broker.cancel('_convey-messages');
|
|
51
58
|
broker.assertExchange('compensate', 'topic');
|
|
52
|
-
this[kCompensateQ] = broker.assertQueue('compensate-q', {durable: true, autoDelete: false});
|
|
53
59
|
broker.subscribeTmp('compensate', 'execute.#', this._onCollect.bind(this), {
|
|
54
60
|
noAck: true,
|
|
55
61
|
consumerTag: '_oncollect-messages',
|
|
56
62
|
});
|
|
57
63
|
|
|
58
|
-
broker.publish('execution', 'execute.detach', cloneContent(executeContent, {
|
|
59
|
-
sourceExchange: 'execution',
|
|
60
|
-
bindExchange: 'compensate',
|
|
61
|
-
}));
|
|
62
|
-
|
|
63
64
|
this[kMessageQ].consume(this._onCompensateApiMessage.bind(this), {
|
|
64
65
|
noAck: true,
|
|
65
66
|
consumerTag: `_oncompensate-${executionId}`,
|
|
@@ -67,27 +68,24 @@ CompensateEventDefinition.prototype.executeCatch = function executeCatch(execute
|
|
|
67
68
|
|
|
68
69
|
if (this[kCompleted]) return;
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
broker.subscribeTmp('api', `activity.#.${executionId}`, onApiMessage, {
|
|
71
|
+
broker.subscribeTmp('api', `activity.#.${parent.executionId}#`, this._onApiMessage.bind(this), {
|
|
72
72
|
noAck: true,
|
|
73
73
|
consumerTag: `_api-${executionId}`,
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
broker.publish('execution', 'execute.detach', cloneContent(executeContent, {
|
|
77
|
+
sourceExchange: 'execution',
|
|
78
78
|
bindExchange: 'compensate',
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
broker.publish('event', 'activity.detach', detachContent);
|
|
79
|
+
expect: 'compensate',
|
|
80
|
+
}));
|
|
83
81
|
};
|
|
84
82
|
|
|
85
83
|
CompensateEventDefinition.prototype.executeThrow = function executeThrow(executeMessage) {
|
|
86
84
|
const executeContent = executeMessage.content;
|
|
87
|
-
const {
|
|
85
|
+
const {parent} = executeContent;
|
|
88
86
|
const parentExecutionId = parent && parent.executionId;
|
|
89
87
|
|
|
90
|
-
this.logger.debug(`<${
|
|
88
|
+
this.logger.debug(`<${parentExecutionId} (${this.id})> throw compensate`);
|
|
91
89
|
|
|
92
90
|
const broker = this.broker;
|
|
93
91
|
const throwContent = cloneContent(executeContent, {
|
|
@@ -101,7 +99,6 @@ CompensateEventDefinition.prototype.executeThrow = function executeThrow(execute
|
|
|
101
99
|
};
|
|
102
100
|
|
|
103
101
|
CompensateEventDefinition.prototype._onCollect = function onCollect(routingKey, message) {
|
|
104
|
-
|
|
105
102
|
switch (routingKey) {
|
|
106
103
|
case 'execute.error':
|
|
107
104
|
case 'execute.completed': {
|
|
@@ -111,67 +108,78 @@ CompensateEventDefinition.prototype._onCollect = function onCollect(routingKey,
|
|
|
111
108
|
};
|
|
112
109
|
|
|
113
110
|
CompensateEventDefinition.prototype._onCompensateApiMessage = function onCompensateApiMessage(routingKey, message) {
|
|
114
|
-
const output = message.content.message;
|
|
115
111
|
this[kCompleted] = true;
|
|
112
|
+
const output = message.content.message;
|
|
113
|
+
const broker = this.broker;
|
|
114
|
+
const executeContent = this[kExecuteMessage].content;
|
|
116
115
|
|
|
117
|
-
this.
|
|
116
|
+
this._stopCollect();
|
|
118
117
|
|
|
119
118
|
this._debug('caught compensate event');
|
|
120
|
-
|
|
121
|
-
const executeContent = this[kExecuteMessage].content;
|
|
119
|
+
|
|
122
120
|
const catchContent = cloneContent(executeContent, {
|
|
123
121
|
message: {...output},
|
|
124
122
|
executionId: executeContent.parent.executionId,
|
|
125
123
|
});
|
|
126
124
|
catchContent.parent = shiftParent(catchContent.parent);
|
|
127
125
|
|
|
128
|
-
|
|
126
|
+
this[kCompensateQ].queueMessage({routingKey: 'execute.compensated'}, cloneContent(executeContent));
|
|
129
127
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
compensateQ.consume(this._onCollected.bind(this), {noAck: true, consumerTag: '_convey-messages'});
|
|
128
|
+
broker.publish('execution', 'execute.compensating', cloneContent(executeContent, {message: {...output}}));
|
|
129
|
+
broker.publish('event', 'activity.catch', catchContent, {type: 'catch'});
|
|
133
130
|
|
|
134
|
-
|
|
131
|
+
return this._compensate();
|
|
132
|
+
};
|
|
135
133
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return broker.publish('execution', 'execute.completed', cloneContent(executeContent, {output, state: 'catch'}));
|
|
139
|
-
}
|
|
134
|
+
CompensateEventDefinition.prototype._compensate = function compensate() {
|
|
135
|
+
return this[kCompensateQ].consume(this._onCollected.bind(this), {noAck: true, consumerTag: '_convey-messages'});
|
|
140
136
|
};
|
|
141
137
|
|
|
142
138
|
CompensateEventDefinition.prototype._onCollected = function onCollected(routingKey, message) {
|
|
139
|
+
if (routingKey === 'execute.compensated') {
|
|
140
|
+
const broker = this.broker;
|
|
141
|
+
broker.cancel('_convey-messages');
|
|
142
|
+
return this.broker.publish('execution', 'execute.completed', cloneContent(message.content, {cancelActivity: false}));
|
|
143
|
+
}
|
|
143
144
|
for (const association of this[kAssociations]) association.take(cloneMessage(message));
|
|
144
145
|
};
|
|
145
146
|
|
|
147
|
+
CompensateEventDefinition.prototype._onDiscardApiMessage = function onDiscardApiMessage(routingKey, message) {
|
|
148
|
+
this[kCompleted] = true;
|
|
149
|
+
this._stop();
|
|
150
|
+
this[kCompensateQ].purge();
|
|
151
|
+
for (const association of this[kAssociations]) association.discard(cloneMessage(message));
|
|
152
|
+
return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content));
|
|
153
|
+
};
|
|
154
|
+
|
|
146
155
|
CompensateEventDefinition.prototype._onApiMessage = function onApiMessage(routingKey, message) {
|
|
147
156
|
const messageType = message.properties.type;
|
|
148
|
-
|
|
149
157
|
switch (messageType) {
|
|
150
158
|
case 'compensate': {
|
|
151
159
|
return this._onCompensateApiMessage(routingKey, message);
|
|
152
160
|
}
|
|
153
161
|
case 'discard': {
|
|
154
|
-
this
|
|
155
|
-
this._stop();
|
|
156
|
-
for (const association of this[kAssociations]) association.discard(cloneMessage(message));
|
|
157
|
-
return this.broker.publish('execution', 'execute.discard', cloneContent(this[kExecuteMessage].content));
|
|
162
|
+
return this._onDiscardApiMessage(routingKey, message);
|
|
158
163
|
}
|
|
159
164
|
case 'stop': {
|
|
160
|
-
this._stop();
|
|
161
|
-
break;
|
|
165
|
+
return this._stop();
|
|
162
166
|
}
|
|
163
167
|
}
|
|
164
168
|
};
|
|
165
169
|
|
|
166
|
-
CompensateEventDefinition.prototype.
|
|
170
|
+
CompensateEventDefinition.prototype._stopCollect = function stopCollect() {
|
|
167
171
|
const broker = this.broker, executionId = this.executionId;
|
|
168
172
|
broker.cancel(`_api-${executionId}`);
|
|
169
173
|
broker.cancel(`_oncompensate-${executionId}`);
|
|
170
174
|
broker.cancel('_oncollect-messages');
|
|
171
|
-
broker.cancel('_convey-messages');
|
|
172
175
|
this[kMessageQ].purge();
|
|
173
176
|
};
|
|
174
177
|
|
|
178
|
+
CompensateEventDefinition.prototype._stop = function stop() {
|
|
179
|
+
this._stopCollect();
|
|
180
|
+
this.broker.cancel('_convey-messages');
|
|
181
|
+
};
|
|
182
|
+
|
|
175
183
|
CompensateEventDefinition.prototype._debug = function debug(msg) {
|
|
176
184
|
this.logger.debug(`<${this.executionId} (${this.activity.id})> ${msg}`);
|
|
177
185
|
};
|
|
@@ -59,9 +59,11 @@ ConditionalEventDefinition.prototype.executeWait = function executeWait(executeM
|
|
|
59
59
|
|
|
60
60
|
ConditionalEventDefinition.prototype.executeCatch = function executeCatch(executeMessage) {
|
|
61
61
|
const executeContent = executeMessage.content;
|
|
62
|
-
const {executionId, index} = executeContent;
|
|
62
|
+
const {executionId, index, parent} = executeContent;
|
|
63
|
+
const parentExecutionId = parent.executionId;
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
const broker = this.broker;
|
|
66
|
+
broker.subscribeTmp('api', `activity.#.${executionId}`, this._onCatchApiMessage.bind(this), {
|
|
65
67
|
noAck: true,
|
|
66
68
|
consumerTag: `_api-${executionId}_${index}`,
|
|
67
69
|
});
|
|
@@ -74,6 +76,14 @@ ConditionalEventDefinition.prototype.executeCatch = function executeCatch(execut
|
|
|
74
76
|
priority: 300,
|
|
75
77
|
consumerTag: `_onend-${executionId}_${index}`,
|
|
76
78
|
});
|
|
79
|
+
|
|
80
|
+
const waitContent = cloneContent(executeContent, {
|
|
81
|
+
executionId: parentExecutionId,
|
|
82
|
+
condition: this.condition,
|
|
83
|
+
});
|
|
84
|
+
waitContent.parent = shiftParent(parent);
|
|
85
|
+
|
|
86
|
+
broker.publish('event', 'activity.wait', waitContent);
|
|
77
87
|
};
|
|
78
88
|
|
|
79
89
|
ConditionalEventDefinition.prototype._onWaitApiMessage = function onWaitApiMessage(routingKey, message) {
|
|
@@ -79,6 +79,8 @@ ErrorEventDefinition.prototype.executeCatch = function executeCatch(executeMessa
|
|
|
79
79
|
consumerTag: `_onerror-${executionId}`,
|
|
80
80
|
});
|
|
81
81
|
broker.publish('execution', 'execute.expect', cloneContent(executeContent, {
|
|
82
|
+
pattern: 'activity.error',
|
|
83
|
+
exchange: 'execution',
|
|
82
84
|
expectRoutingKey,
|
|
83
85
|
expect: {...info.message},
|
|
84
86
|
}));
|
|
@@ -96,7 +96,7 @@ BoundaryEventBehaviour.prototype._onExecutionMessage = function onExecutionMessa
|
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, {content}) {
|
|
99
|
-
if (!this.cancelActivity && !content.cancelActivity) {
|
|
99
|
+
if (content.cancelActivity === false || !this.cancelActivity && !content.cancelActivity) {
|
|
100
100
|
this._stop();
|
|
101
101
|
return this.broker.publish('execution', 'execute.completed', cloneContent(content, {isDefinitionScope: false, cancelActivity: false}));
|
|
102
102
|
}
|
|
@@ -106,6 +106,7 @@ BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, {content
|
|
|
106
106
|
const inbound = this[kExecuteMessage].content.inbound;
|
|
107
107
|
const attachedToContent = inbound && inbound[0];
|
|
108
108
|
const attachedTo = this.attachedTo;
|
|
109
|
+
|
|
109
110
|
this.activity.logger.debug(`<${this.executionId} (${this.id})> cancel ${attachedTo.status} activity <${attachedToContent.executionId} (${attachedToContent.id})>`);
|
|
110
111
|
|
|
111
112
|
attachedTo.getApi({content: attachedToContent}).discard();
|
|
@@ -113,6 +114,7 @@ BoundaryEventBehaviour.prototype._onCompleted = function onCompleted(_, {content
|
|
|
113
114
|
|
|
114
115
|
BoundaryEventBehaviour.prototype._onAttachedLeave = function onAttachedLeave(_, {content}) {
|
|
115
116
|
if (content.id !== this.attachedTo.id) return;
|
|
117
|
+
|
|
116
118
|
this._stop();
|
|
117
119
|
const completeContent = this[kCompleteContent];
|
|
118
120
|
if (!completeContent) return this.broker.publish('execution', 'execute.discard', this[kExecuteMessage].content);
|
|
@@ -120,24 +122,26 @@ BoundaryEventBehaviour.prototype._onAttachedLeave = function onAttachedLeave(_,
|
|
|
120
122
|
};
|
|
121
123
|
|
|
122
124
|
BoundaryEventBehaviour.prototype._onExpectMessage = function onExpectMessage(_, {content}) {
|
|
123
|
-
const {executionId, expectRoutingKey} = content;
|
|
125
|
+
const {executionId, expectRoutingKey, pattern, exchange} = content;
|
|
124
126
|
const attachedTo = this.attachedTo;
|
|
125
127
|
|
|
126
128
|
const errorConsumerTag = `_bound-error-listener-${executionId}`;
|
|
127
129
|
this[kAttachedTags].push(errorConsumerTag);
|
|
128
130
|
|
|
129
|
-
attachedTo.broker.subscribeTmp('event',
|
|
130
|
-
if (
|
|
131
|
-
this.broker.publish(
|
|
131
|
+
attachedTo.broker.subscribeTmp('event', pattern, (__, message) => {
|
|
132
|
+
if (message.content.id !== attachedTo.id) return;
|
|
133
|
+
this.broker.publish(exchange, expectRoutingKey, cloneContent(message.content, {attachedTo: attachedTo.id}), {...message.properties, mandatory: false});
|
|
132
134
|
}, {
|
|
133
135
|
noAck: true,
|
|
134
136
|
consumerTag: errorConsumerTag,
|
|
135
|
-
priority:
|
|
137
|
+
priority: 400,
|
|
136
138
|
});
|
|
137
139
|
};
|
|
138
140
|
|
|
139
|
-
BoundaryEventBehaviour.prototype._onDetachMessage = function onDetachMessage(_,
|
|
140
|
-
const
|
|
141
|
+
BoundaryEventBehaviour.prototype._onDetachMessage = function onDetachMessage(_, message) {
|
|
142
|
+
const content = message.content;
|
|
143
|
+
const {executionId, parent} = this[kExecuteMessage].content;
|
|
144
|
+
const id = this.id, attachedTo = this.attachedTo;
|
|
141
145
|
this.activity.logger.debug(`<${executionId} (${id})> detach from activity <${attachedTo.id}>`);
|
|
142
146
|
this._stop(true);
|
|
143
147
|
|
|
@@ -157,6 +161,14 @@ BoundaryEventBehaviour.prototype._onDetachMessage = function onDetachMessage(_,
|
|
|
157
161
|
cloneMessage,
|
|
158
162
|
});
|
|
159
163
|
|
|
164
|
+
const detachContent = cloneContent(content, {
|
|
165
|
+
executionId,
|
|
166
|
+
});
|
|
167
|
+
detachContent.parent = parent;
|
|
168
|
+
|
|
169
|
+
this.activity.removeInboundListeners();
|
|
170
|
+
broker.publish('event', 'activity.detach', detachContent);
|
|
171
|
+
|
|
160
172
|
broker.subscribeOnce('execution', 'execute.bound.completed', (__, {content: completeContent}) => {
|
|
161
173
|
this._stop();
|
|
162
174
|
this.broker.publish('execution', 'execute.completed', cloneContent(completeContent));
|
package/src/flows/Association.js
CHANGED
|
@@ -20,7 +20,6 @@ export default function Association(associationDef, {environment}) {
|
|
|
20
20
|
const logger = this.logger = environment.Logger(type.toLowerCase());
|
|
21
21
|
|
|
22
22
|
this[kCounters] = {
|
|
23
|
-
complete: 0,
|
|
24
23
|
take: 0,
|
|
25
24
|
discard: 0,
|
|
26
25
|
};
|
|
@@ -59,15 +58,6 @@ Association.prototype.discard = function discard(content = {}) {
|
|
|
59
58
|
return true;
|
|
60
59
|
};
|
|
61
60
|
|
|
62
|
-
Association.prototype.complete = function complete(content = {}) {
|
|
63
|
-
this.logger.debug(`<${this.id}> completed target <${this.targetId}>`);
|
|
64
|
-
++this[kCounters].complete;
|
|
65
|
-
|
|
66
|
-
this._publishEvent('complete', content);
|
|
67
|
-
|
|
68
|
-
return true;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
61
|
Association.prototype.getState = function getState() {
|
|
72
62
|
return this._createMessageContent({
|
|
73
63
|
counters: this.counters,
|
|
@@ -40,7 +40,6 @@ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage)
|
|
|
40
40
|
|
|
41
41
|
const broker = this.activity.broker;
|
|
42
42
|
broker.subscribeOnce('api', `activity.stop.${executionId}`, () => this._stop(), {
|
|
43
|
-
noAck: true,
|
|
44
43
|
consumerTag: '_api-stop-execution',
|
|
45
44
|
});
|
|
46
45
|
|
|
@@ -49,7 +48,7 @@ EventBasedGatewayBehaviour.prototype.execute = function execute(executeMessage)
|
|
|
49
48
|
};
|
|
50
49
|
|
|
51
50
|
EventBasedGatewayBehaviour.prototype._onTargetCompleted = function onTargetCompleted(executeMessage, _, message, owner) {
|
|
52
|
-
const {id: targetId,
|
|
51
|
+
const {id: targetId, executionId: targetExecutionId} = message.content;
|
|
53
52
|
const executeContent = executeMessage.content;
|
|
54
53
|
const executionId = executeContent.executionId;
|
|
55
54
|
this.activity.logger.debug(`<${executionId} (${this.id})> <${targetExecutionId}> completed run, discarding the rest`);
|
package/src/process/Process.js
CHANGED
|
@@ -107,6 +107,12 @@ Object.defineProperty(Process.prototype, 'status', {
|
|
|
107
107
|
},
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
+
Object.defineProperty(Process.prototype, 'activityStatus', {
|
|
111
|
+
get() {
|
|
112
|
+
return this[kExec].execution && this[kExec].execution.activityStatus || 'idle';
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
|
|
110
116
|
Process.prototype.init = function init(useAsExecutionId) {
|
|
111
117
|
const exec = this[kExec];
|
|
112
118
|
const initExecutionId = exec.initExecutionId = useAsExecutionId || getUniqueId(this.id);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {ProcessApi} from '../Api.js';
|
|
2
2
|
import {cloneContent, cloneMessage, pushParent} from '../messageHelper.js';
|
|
3
3
|
import {getUniqueId} from '../shared.js';
|
|
4
|
+
import {ActivityTracker} from '../Tracker.js';
|
|
4
5
|
|
|
5
6
|
export default ProcessExecution;
|
|
6
7
|
|
|
@@ -13,14 +14,16 @@ const kMessageHandlers = Symbol.for('messageHandlers');
|
|
|
13
14
|
const kParent = Symbol.for('parent');
|
|
14
15
|
const kStatus = Symbol.for('status');
|
|
15
16
|
const kStopped = Symbol.for('stopped');
|
|
17
|
+
const kTracker = Symbol.for('activity tracker');
|
|
16
18
|
|
|
17
19
|
function ProcessExecution(parentActivity, context) {
|
|
18
|
-
const {id, type, broker, isSubProcess} = parentActivity;
|
|
20
|
+
const {id, type, broker, isSubProcess, isTransaction} = parentActivity;
|
|
19
21
|
|
|
20
22
|
this[kParent] = parentActivity;
|
|
21
23
|
this.id = id;
|
|
22
24
|
this.type = type;
|
|
23
25
|
this.isSubProcess = isSubProcess;
|
|
26
|
+
this.isTransaction = isSubProcess && isTransaction;
|
|
24
27
|
this.broker = broker;
|
|
25
28
|
this.environment = context.environment;
|
|
26
29
|
this.context = context;
|
|
@@ -44,6 +47,7 @@ function ProcessExecution(parentActivity, context) {
|
|
|
44
47
|
this[kStopped] = false;
|
|
45
48
|
this[kActivated] = false;
|
|
46
49
|
this[kStatus] = 'init';
|
|
50
|
+
this[kTracker] = new ActivityTracker(id);
|
|
47
51
|
this.executionId = undefined;
|
|
48
52
|
|
|
49
53
|
this[kMessageHandlers] = {
|
|
@@ -87,6 +91,12 @@ Object.defineProperty(ProcessExecution.prototype, 'isRunning', {
|
|
|
87
91
|
},
|
|
88
92
|
});
|
|
89
93
|
|
|
94
|
+
Object.defineProperty(ProcessExecution.prototype, 'activityStatus', {
|
|
95
|
+
get() {
|
|
96
|
+
return this[kTracker].activityStatus;
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
90
100
|
ProcessExecution.prototype.execute = function execute(executeMessage) {
|
|
91
101
|
if (!executeMessage) throw new Error('Process execution requires message');
|
|
92
102
|
if (!executeMessage.content || !executeMessage.content.executionId) throw new Error('Process execution requires execution id');
|
|
@@ -139,6 +149,7 @@ ProcessExecution.prototype.resume = function resume() {
|
|
|
139
149
|
const status = this.status;
|
|
140
150
|
if (status === 'init') return this._start();
|
|
141
151
|
|
|
152
|
+
const tracker = this[kTracker];
|
|
142
153
|
for (const msg of postponed.slice()) {
|
|
143
154
|
const activity = this.getActivityById(msg.content.id);
|
|
144
155
|
if (!activity) continue;
|
|
@@ -148,6 +159,8 @@ ProcessExecution.prototype.resume = function resume() {
|
|
|
148
159
|
msg.ack();
|
|
149
160
|
continue;
|
|
150
161
|
}
|
|
162
|
+
|
|
163
|
+
tracker.track(msg.fields.routingKey, msg);
|
|
151
164
|
activity.resume();
|
|
152
165
|
}
|
|
153
166
|
|
|
@@ -261,6 +274,14 @@ ProcessExecution.prototype.discard = function discard() {
|
|
|
261
274
|
}, {type: 'discard'});
|
|
262
275
|
};
|
|
263
276
|
|
|
277
|
+
ProcessExecution.prototype.cancel = function discard() {
|
|
278
|
+
return this[kActivityQ].queueMessage({ routingKey: 'execution.cancel' }, {
|
|
279
|
+
id: this.id,
|
|
280
|
+
type: this.type,
|
|
281
|
+
executionId: this.executionId,
|
|
282
|
+
}, { type: 'cancel' });
|
|
283
|
+
};
|
|
284
|
+
|
|
264
285
|
ProcessExecution.prototype.getState = function getState() {
|
|
265
286
|
const {children, flows, outboundMessageFlows, associations} = this[kElements];
|
|
266
287
|
return {
|
|
@@ -291,6 +312,10 @@ ProcessExecution.prototype.getSequenceFlows = function getSequenceFlows() {
|
|
|
291
312
|
return this[kElements].flows.slice();
|
|
292
313
|
};
|
|
293
314
|
|
|
315
|
+
ProcessExecution.prototype.getAssociations = function getAssociations() {
|
|
316
|
+
return this[kElements].associations.slice();
|
|
317
|
+
};
|
|
318
|
+
|
|
294
319
|
ProcessExecution.prototype.getApi = function getApi(message) {
|
|
295
320
|
if (!message) return ProcessApi(this.broker, this[kExecuteMessage]);
|
|
296
321
|
|
|
@@ -332,6 +357,7 @@ ProcessExecution.prototype._start = function start() {
|
|
|
332
357
|
}
|
|
333
358
|
|
|
334
359
|
for (const a of startActivities) a.init();
|
|
360
|
+
this[kStatus] = 'executing';
|
|
335
361
|
for (const a of startActivities) a.run();
|
|
336
362
|
|
|
337
363
|
postponed.splice(0);
|
|
@@ -478,10 +504,10 @@ ProcessExecution.prototype._onActivityEvent = function onActivityEvent(routingKe
|
|
|
478
504
|
|
|
479
505
|
if (delegate) delegate = this._onDelegateEvent(message);
|
|
480
506
|
|
|
507
|
+
this[kTracker].track(routingKey, message);
|
|
481
508
|
this.broker.publish('event', routingKey, content, {...message.properties, delegate, mandatory: false});
|
|
482
509
|
if (shaking) return this._onShookEnd(message);
|
|
483
510
|
if (!isDirectChild) return;
|
|
484
|
-
if (content.isAssociation) return;
|
|
485
511
|
|
|
486
512
|
switch (routingKey) {
|
|
487
513
|
case 'process.terminate':
|
|
@@ -508,6 +534,16 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey,
|
|
|
508
534
|
case 'execution.discard':
|
|
509
535
|
message.ack();
|
|
510
536
|
return this._onDiscard(message);
|
|
537
|
+
case 'execution.discard.detached': {
|
|
538
|
+
message.ack();
|
|
539
|
+
for (const detached of this[kElements].detachedActivities) {
|
|
540
|
+
this._getChildApi(detached).discard();
|
|
541
|
+
}
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
case 'execution.cancel':
|
|
545
|
+
message.ack();
|
|
546
|
+
return this._onCancel(message);
|
|
511
547
|
case 'activity.error.caught': {
|
|
512
548
|
const prevMsg = this[kElements].postponed.find((msg) => {
|
|
513
549
|
return msg.content.executionId === content.executionId;
|
|
@@ -515,7 +551,6 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey,
|
|
|
515
551
|
if (!prevMsg) return message.ack();
|
|
516
552
|
break;
|
|
517
553
|
}
|
|
518
|
-
case 'activity.compensation.end':
|
|
519
554
|
case 'flow.looped':
|
|
520
555
|
case 'activity.leave':
|
|
521
556
|
return this._onChildCompleted(message);
|
|
@@ -528,14 +563,16 @@ ProcessExecution.prototype._onChildMessage = function onChildMessage(routingKey,
|
|
|
528
563
|
this[kElements].detachedActivities.push(cloneMessage(message));
|
|
529
564
|
break;
|
|
530
565
|
}
|
|
566
|
+
case 'activity.cancel': {
|
|
567
|
+
if (this.isTransaction) this._onCancel(message);
|
|
568
|
+
break;
|
|
569
|
+
}
|
|
531
570
|
case 'activity.discard':
|
|
532
|
-
case 'activity.compensation.start':
|
|
533
571
|
case 'activity.enter': {
|
|
534
|
-
this[kStatus] = 'executing';
|
|
535
572
|
if (!content.inbound) break;
|
|
536
573
|
|
|
537
574
|
for (const inbound of content.inbound) {
|
|
538
|
-
if (!inbound.isSequenceFlow) continue;
|
|
575
|
+
if (!inbound.isSequenceFlow && !inbound.isAssociation) continue;
|
|
539
576
|
const inboundMessage = this._popPostponed(inbound);
|
|
540
577
|
if (inboundMessage) inboundMessage.ack();
|
|
541
578
|
}
|
|
@@ -566,7 +603,7 @@ ProcessExecution.prototype._popPostponed = function popPostponed(byContent) {
|
|
|
566
603
|
const {postponed, detachedActivities} = this[kElements];
|
|
567
604
|
|
|
568
605
|
const postponedIdx = postponed.findIndex((msg) => {
|
|
569
|
-
if (msg.content.isSequenceFlow) return msg.content.sequenceId === byContent.sequenceId;
|
|
606
|
+
if (msg.content.isSequenceFlow || msg.content.isAssociation) return msg.content.sequenceId === byContent.sequenceId;
|
|
570
607
|
return msg.content.executionId === byContent.executionId;
|
|
571
608
|
});
|
|
572
609
|
|
|
@@ -598,9 +635,12 @@ ProcessExecution.prototype._onChildCompleted = function onChildCompleted(message
|
|
|
598
635
|
|
|
599
636
|
this._debug(`left <${id}> (${type}), pending runs ${postponedCount}, ${postponed.map((a) => a.content.id).join(',')}`);
|
|
600
637
|
|
|
601
|
-
if (postponedCount === detachedActivities.length) {
|
|
602
|
-
|
|
603
|
-
|
|
638
|
+
if (postponedCount && postponedCount === detachedActivities.length) {
|
|
639
|
+
return this[kActivityQ].queueMessage({ routingKey: 'execution.discard.detached' }, {
|
|
640
|
+
id: this.id,
|
|
641
|
+
type: this.type,
|
|
642
|
+
executionId: this.executionId,
|
|
643
|
+
}, { type: 'cancel' });
|
|
604
644
|
}
|
|
605
645
|
|
|
606
646
|
if (isEnd && startActivities.length) {
|
|
@@ -636,35 +676,47 @@ ProcessExecution.prototype._onDiscard = function onDiscard() {
|
|
|
636
676
|
const running = this[kElements].postponed.splice(0);
|
|
637
677
|
this._debug(`discard process execution (discard child executions ${running.length})`);
|
|
638
678
|
|
|
639
|
-
|
|
640
|
-
|
|
679
|
+
if (this.isSubProcess) {
|
|
680
|
+
this.stop();
|
|
681
|
+
} else {
|
|
682
|
+
for (const flow of this.getSequenceFlows()) flow.stop();
|
|
683
|
+
for (const flow of this.getAssociations()) flow.stop();
|
|
684
|
+
for (const msg of running) this._getChildApi(msg).discard();
|
|
685
|
+
}
|
|
641
686
|
|
|
642
687
|
this[kActivityQ].purge();
|
|
643
688
|
return this._complete('discard');
|
|
644
689
|
};
|
|
645
690
|
|
|
646
|
-
ProcessExecution.prototype.
|
|
647
|
-
const
|
|
648
|
-
const
|
|
649
|
-
if (message.properties.delegate) {
|
|
650
|
-
const correlationId = message.properties.correlationId || getUniqueId(executionId);
|
|
651
|
-
this._debug(`delegate api ${routingKey} message to children, with correlationId <${correlationId}>`);
|
|
652
|
-
|
|
653
|
-
let consumed = false;
|
|
654
|
-
broker.subscribeTmp('event', 'activity.consumed', (_, msg) => {
|
|
655
|
-
if (msg.properties.correlationId === correlationId) {
|
|
656
|
-
consumed = true;
|
|
657
|
-
this._debug(`delegated api message was consumed by ${msg.content ? msg.content.executionId : 'unknown'}`);
|
|
658
|
-
}
|
|
659
|
-
}, {consumerTag: `_ct-delegate-${correlationId}`, noAck: true});
|
|
691
|
+
ProcessExecution.prototype._onCancel = function onCancel() {
|
|
692
|
+
const running = this[kElements].postponed.slice(0);
|
|
693
|
+
const isTransaction = this.isTransaction;
|
|
660
694
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
695
|
+
if (isTransaction) {
|
|
696
|
+
this._debug(`cancel transaction execution (cancel child executions ${running.length})`);
|
|
697
|
+
this[kStatus] = 'cancel';
|
|
698
|
+
this.broker.publish('event', 'transaction.cancel', cloneMessage(this[kExecuteMessage], {
|
|
699
|
+
state: 'cancel',
|
|
700
|
+
}));
|
|
701
|
+
|
|
702
|
+
for (const msg of running) {
|
|
703
|
+
if (msg.content.expect === 'compensate') {
|
|
704
|
+
this._getChildApi(msg).sendApiMessage('compensate');
|
|
705
|
+
} else if (!msg.content.isForCompensation) {
|
|
706
|
+
this._getChildApi(msg).discard();
|
|
707
|
+
}
|
|
665
708
|
}
|
|
709
|
+
} else {
|
|
710
|
+
this._debug(`cancel process execution (cancel child executions ${running.length})`);
|
|
711
|
+
for (const msg of running) {
|
|
712
|
+
this._getChildApi(msg).discard();
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
};
|
|
666
716
|
|
|
667
|
-
|
|
717
|
+
ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, message) {
|
|
718
|
+
if (message.properties.delegate) {
|
|
719
|
+
return this._delegateApiMessage(routingKey, message);
|
|
668
720
|
}
|
|
669
721
|
|
|
670
722
|
if (this.id !== message.content.id) {
|
|
@@ -676,19 +728,56 @@ ProcessExecution.prototype._onApiMessage = function onApiMessage(routingKey, mes
|
|
|
676
728
|
if (this.executionId !== message.content.executionId) return;
|
|
677
729
|
|
|
678
730
|
switch (message.properties.type) {
|
|
731
|
+
case 'cancel':
|
|
732
|
+
return this.cancel(message);
|
|
679
733
|
case 'discard':
|
|
680
734
|
return this.discard(message);
|
|
681
735
|
case 'stop':
|
|
682
|
-
this[kActivityQ].queueMessage({routingKey: 'execution.stop'}, cloneContent(message.content), {persistent: false});
|
|
736
|
+
this[kActivityQ].queueMessage({ routingKey: 'execution.stop' }, cloneContent(message.content), { persistent: false });
|
|
683
737
|
break;
|
|
684
738
|
}
|
|
685
739
|
};
|
|
686
740
|
|
|
741
|
+
ProcessExecution.prototype._delegateApiMessage = function delegateApiMessage(routingKey, message, continueOnConsumed) {
|
|
742
|
+
const correlationId = message.properties.correlationId || getUniqueId(this.executionId);
|
|
743
|
+
this._debug(`delegate api ${routingKey} message to children, with correlationId <${correlationId}>`);
|
|
744
|
+
|
|
745
|
+
const broker = this.broker;
|
|
746
|
+
let consumed = false;
|
|
747
|
+
broker.subscribeTmp('event', 'activity.consumed', (_, msg) => {
|
|
748
|
+
if (msg.properties.correlationId === correlationId) {
|
|
749
|
+
consumed = true;
|
|
750
|
+
this._debug(`delegated api message was consumed by ${msg.content ? msg.content.executionId : 'unknown'}`);
|
|
751
|
+
}
|
|
752
|
+
}, { consumerTag: `_ct-delegate-${correlationId}`, noAck: true });
|
|
753
|
+
|
|
754
|
+
for (const child of this[kElements].children) {
|
|
755
|
+
if (child.placeholder) continue;
|
|
756
|
+
child.broker.publish('api', routingKey, cloneContent(message.content), message.properties);
|
|
757
|
+
if (consumed && !continueOnConsumed) break;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
return broker.cancel(`_ct-delegate-${correlationId}`);
|
|
761
|
+
};
|
|
762
|
+
|
|
687
763
|
ProcessExecution.prototype._complete = function complete(completionType, content) {
|
|
688
764
|
this._deactivate();
|
|
689
|
-
this._debug(`process execution ${completionType}`);
|
|
690
765
|
this[kCompleted] = true;
|
|
691
|
-
|
|
766
|
+
|
|
767
|
+
const status = this.status;
|
|
768
|
+
switch (this.status) {
|
|
769
|
+
case 'cancel':
|
|
770
|
+
this._debug('process execution cancelled');
|
|
771
|
+
case 'discard':
|
|
772
|
+
completionType = status;
|
|
773
|
+
break;
|
|
774
|
+
case 'terminated':
|
|
775
|
+
break;
|
|
776
|
+
default:
|
|
777
|
+
this._debug(`process execution ${completionType}`);
|
|
778
|
+
this[kStatus] = completionType;
|
|
779
|
+
}
|
|
780
|
+
|
|
692
781
|
const broker = this.broker;
|
|
693
782
|
this[kActivityQ].delete();
|
|
694
783
|
|
|
@@ -705,11 +794,12 @@ ProcessExecution.prototype._terminate = function terminate(message) {
|
|
|
705
794
|
|
|
706
795
|
const running = this[kElements].postponed.splice(0);
|
|
707
796
|
for (const flow of this.getSequenceFlows()) flow.stop();
|
|
797
|
+
for (const flow of this.getAssociations()) flow.stop();
|
|
708
798
|
|
|
709
799
|
for (const msg of running) {
|
|
710
|
-
const {id: postponedId, isSequenceFlow} = msg.content;
|
|
800
|
+
const {id: postponedId, isSequenceFlow, isAssociation} = msg.content;
|
|
711
801
|
if (postponedId === message.content.id) continue;
|
|
712
|
-
if (isSequenceFlow) continue;
|
|
802
|
+
if (isSequenceFlow || isAssociation) continue;
|
|
713
803
|
this._getChildApi(msg).stop();
|
|
714
804
|
msg.ack();
|
|
715
805
|
}
|