bpmn-elements 5.1.3 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/CHANGELOG.md +322 -0
  2. package/README.md +9 -3
  3. package/dist/index.js +71 -39
  4. package/dist/src/Api.js +77 -76
  5. package/dist/src/Context.js +169 -164
  6. package/dist/src/Environment.js +90 -102
  7. package/dist/src/EventBroker.js +89 -88
  8. package/dist/src/ExtensionsMapper.js +2 -2
  9. package/dist/src/MessageFormatter.js +164 -95
  10. package/dist/src/Scripts.js +6 -2
  11. package/dist/src/Timers.js +4 -6
  12. package/dist/src/activity/Activity.js +1108 -901
  13. package/dist/src/activity/ActivityExecution.js +342 -297
  14. package/dist/src/activity/Dummy.js +3 -3
  15. package/dist/src/definition/Definition.js +498 -444
  16. package/dist/src/definition/DefinitionExecution.js +722 -409
  17. package/dist/src/error/Errors.js +17 -7
  18. package/dist/src/eventDefinitions/CancelEventDefinition.js +190 -150
  19. package/dist/src/eventDefinitions/CompensateEventDefinition.js +194 -161
  20. package/dist/src/eventDefinitions/ConditionalEventDefinition.js +197 -135
  21. package/dist/src/eventDefinitions/ErrorEventDefinition.js +207 -165
  22. package/dist/src/eventDefinitions/EscalationEventDefinition.js +175 -141
  23. package/dist/src/eventDefinitions/EventDefinitionExecution.js +157 -129
  24. package/dist/src/eventDefinitions/LinkEventDefinition.js +174 -149
  25. package/dist/src/eventDefinitions/MessageEventDefinition.js +213 -176
  26. package/dist/src/eventDefinitions/SignalEventDefinition.js +203 -161
  27. package/dist/src/eventDefinitions/TerminateEventDefinition.js +21 -23
  28. package/dist/src/eventDefinitions/TimerEventDefinition.js +243 -228
  29. package/dist/src/events/BoundaryEvent.js +180 -144
  30. package/dist/src/events/EndEvent.js +18 -23
  31. package/dist/src/events/IntermediateCatchEvent.js +44 -58
  32. package/dist/src/events/IntermediateThrowEvent.js +18 -23
  33. package/dist/src/events/StartEvent.js +109 -94
  34. package/dist/src/flows/Association.js +94 -101
  35. package/dist/src/flows/MessageFlow.js +86 -103
  36. package/dist/src/flows/SequenceFlow.js +172 -184
  37. package/dist/src/gateways/EventBasedGateway.js +88 -84
  38. package/dist/src/gateways/ExclusiveGateway.js +13 -16
  39. package/dist/src/gateways/InclusiveGateway.js +11 -14
  40. package/dist/src/gateways/ParallelGateway.js +11 -14
  41. package/dist/src/getPropertyValue.js +34 -34
  42. package/dist/src/io/BpmnIO.js +31 -0
  43. package/dist/src/io/EnvironmentDataObject.js +33 -29
  44. package/dist/src/io/EnvironmentDataStore.js +52 -0
  45. package/dist/src/io/EnvironmentDataStoreReference.js +52 -0
  46. package/dist/src/io/InputOutputSpecification.js +177 -168
  47. package/dist/src/io/Properties.js +252 -0
  48. package/dist/src/messageHelper.js +1 -1
  49. package/dist/src/process/Process.js +433 -359
  50. package/dist/src/process/ProcessExecution.js +744 -645
  51. package/dist/src/shared.js +3 -6
  52. package/dist/src/tasks/CallActivity.js +160 -0
  53. package/dist/src/tasks/LoopCharacteristics.js +309 -330
  54. package/dist/src/tasks/ReceiveTask.js +233 -182
  55. package/dist/src/tasks/ScriptTask.js +35 -41
  56. package/dist/src/tasks/ServiceImplementation.js +13 -20
  57. package/dist/src/tasks/ServiceTask.js +82 -75
  58. package/dist/src/tasks/SignalTask.js +97 -93
  59. package/dist/src/tasks/StandardLoopCharacteristics.js +1 -1
  60. package/dist/src/tasks/SubProcess.js +195 -175
  61. package/dist/src/tasks/Task.js +17 -19
  62. package/index.js +8 -0
  63. package/package.json +16 -15
  64. package/src/Api.js +65 -59
  65. package/src/Context.js +142 -132
  66. package/src/Environment.js +88 -100
  67. package/src/EventBroker.js +67 -68
  68. package/src/ExtensionsMapper.js +2 -2
  69. package/src/MessageFormatter.js +132 -74
  70. package/src/Timers.js +4 -4
  71. package/src/activity/Activity.js +916 -757
  72. package/src/activity/ActivityExecution.js +293 -247
  73. package/src/activity/Dummy.js +2 -2
  74. package/src/definition/Definition.js +436 -401
  75. package/src/definition/DefinitionExecution.js +603 -343
  76. package/src/error/Errors.js +11 -6
  77. package/src/eventDefinitions/CancelEventDefinition.js +164 -121
  78. package/src/eventDefinitions/CompensateEventDefinition.js +158 -124
  79. package/src/eventDefinitions/ConditionalEventDefinition.js +147 -104
  80. package/src/eventDefinitions/ErrorEventDefinition.js +190 -131
  81. package/src/eventDefinitions/EscalationEventDefinition.js +139 -101
  82. package/src/eventDefinitions/EventDefinitionExecution.js +127 -95
  83. package/src/eventDefinitions/LinkEventDefinition.js +160 -129
  84. package/src/eventDefinitions/MessageEventDefinition.js +178 -121
  85. package/src/eventDefinitions/SignalEventDefinition.js +162 -106
  86. package/src/eventDefinitions/TerminateEventDefinition.js +19 -19
  87. package/src/eventDefinitions/TimerEventDefinition.js +202 -167
  88. package/src/events/BoundaryEvent.js +156 -115
  89. package/src/events/EndEvent.js +15 -18
  90. package/src/events/IntermediateCatchEvent.js +40 -44
  91. package/src/events/IntermediateThrowEvent.js +15 -18
  92. package/src/events/StartEvent.js +84 -50
  93. package/src/flows/Association.js +98 -113
  94. package/src/flows/MessageFlow.js +81 -97
  95. package/src/flows/SequenceFlow.js +145 -163
  96. package/src/gateways/EventBasedGateway.js +75 -68
  97. package/src/gateways/ExclusiveGateway.js +8 -13
  98. package/src/gateways/InclusiveGateway.js +8 -13
  99. package/src/gateways/ParallelGateway.js +8 -13
  100. package/src/getPropertyValue.js +34 -33
  101. package/src/io/BpmnIO.js +20 -0
  102. package/src/io/EnvironmentDataObject.js +29 -18
  103. package/src/io/EnvironmentDataStore.js +33 -0
  104. package/src/io/EnvironmentDataStoreReference.js +33 -0
  105. package/src/io/InputOutputSpecification.js +154 -157
  106. package/src/io/Properties.js +199 -0
  107. package/src/process/Process.js +374 -333
  108. package/src/process/ProcessExecution.js +606 -554
  109. package/src/shared.js +1 -5
  110. package/src/tasks/CallActivity.js +130 -0
  111. package/src/tasks/LoopCharacteristics.js +290 -289
  112. package/src/tasks/ReceiveTask.js +174 -107
  113. package/src/tasks/ScriptTask.js +27 -30
  114. package/src/tasks/ServiceImplementation.js +13 -18
  115. package/src/tasks/ServiceTask.js +67 -60
  116. package/src/tasks/SignalTask.js +77 -52
  117. package/src/tasks/StandardLoopCharacteristics.js +1 -1
  118. package/src/tasks/SubProcess.js +184 -157
  119. package/src/tasks/Task.js +15 -19
@@ -2,122 +2,110 @@ import Expressions from './Expressions';
2
2
  import {Scripts as IScripts} from './Scripts';
3
3
  import {Timers} from './Timers';
4
4
 
5
+ const optionsSymbol = Symbol.for('options');
6
+ const variablesSymbol = Symbol.for('variables');
7
+
5
8
  const defaultOptions = ['extensions', 'output', 'services', 'scripts', 'settings', 'variables', 'Logger'];
6
9
 
7
10
  export default function Environment(options = {}) {
8
- const initialOptions = validateOptions(options);
9
-
10
- let variables = options.variables || {};
11
- const settings = {...options.settings};
12
- const output = options.output || {};
13
- const services = options.services || {};
14
- const scripts = options.scripts || IScripts();
15
- const timers = options.timers || Timers();
16
- const expressions = options.expressions || Expressions();
17
- const Logger = options.Logger || DummyLogger;
18
- const extensions = options.extensions;
19
-
20
- const environmentApi = {
21
- options: initialOptions,
22
- expressions,
23
- extensions,
24
- output,
25
- scripts,
26
- services,
27
- settings,
28
- timers,
29
- get variables() {
30
- return variables;
31
- },
32
- addService,
33
- assignVariables,
34
- clone,
35
- getScript,
36
- getServiceByName,
37
- getState,
38
- registerScript,
39
- resolveExpression,
40
- recover,
41
- Logger,
42
- };
43
-
44
- return environmentApi;
45
-
46
- function getState() {
47
- return {
48
- settings: {...settings},
49
- variables: {...variables},
50
- output: {...output},
51
- };
52
- }
11
+ this[optionsSymbol] = options;
12
+ this.options = validateOptions(options);
13
+
14
+ this.expressions = options.expressions || Expressions();
15
+ this.extensions = options.extensions;
16
+ this.output = options.output || {};
17
+ this.scripts = options.scripts || IScripts();
18
+ this.services = options.services || {};
19
+ this.settings = {...options.settings};
20
+ this.timers = options.timers || Timers();
21
+ this.Logger = options.Logger || DummyLogger;
22
+ this[variablesSymbol] = options.variables || {};
23
+ }
53
24
 
54
- function recover(state) {
55
- if (!state) return environmentApi;
25
+ const proto = Environment.prototype;
56
26
 
57
- const recoverOptions = validateOptions(state);
58
- Object.assign(options, recoverOptions);
27
+ Object.defineProperty(proto, 'variables', {
28
+ enumerable: true,
29
+ get() {
30
+ return this[variablesSymbol];
31
+ },
32
+ });
59
33
 
60
- if (state.settings) Object.assign(settings, state.settings);
61
- if (state.variables) Object.assign(variables, state.variables);
62
- if (state.output) Object.assign(output, state.output);
34
+ proto.getState = function getState() {
35
+ return {
36
+ settings: {...this.settings},
37
+ variables: {...this.variables},
38
+ output: {...this.output},
39
+ };
40
+ };
41
+
42
+ proto.recover = function recover(state) {
43
+ if (!state) return this;
44
+
45
+ const recoverOptions = validateOptions(state);
46
+ Object.assign(this[optionsSymbol], recoverOptions);
47
+
48
+ if (state.settings) Object.assign(this.settings, state.settings);
49
+ if (state.variables) Object.assign(this[variablesSymbol], state.variables);
50
+ if (state.output) Object.assign(this.output, state.output);
51
+
52
+ return this;
53
+ };
54
+
55
+ proto.clone = function clone(overrideOptions = {}) {
56
+ const services = this.services;
57
+ const newOptions = {
58
+ settings: {...this.settings},
59
+ variables: {...this.variables},
60
+ output: {...this.output},
61
+ Logger: this.Logger,
62
+ extensions: this.extensions,
63
+ scripts: this.scripts,
64
+ timers: this.timers,
65
+ expressions: this.expressions,
66
+ ...this.options,
67
+ ...overrideOptions,
68
+ services,
69
+ };
63
70
 
64
- return environmentApi;
65
- }
71
+ if (overrideOptions.services) newOptions.services = {...services, ...overrideOptions.services};
66
72
 
67
- function clone(overrideOptions = {}) {
68
- const newOptions = {
69
- settings: {...settings},
70
- variables: {...variables},
71
- output: {...output},
72
- Logger,
73
- extensions,
74
- scripts,
75
- timers,
76
- expressions,
77
- ...initialOptions,
78
- ...overrideOptions,
79
- services,
80
- };
81
-
82
- if (overrideOptions.services) newOptions.services = {...services, ...overrideOptions.services};
83
-
84
- return Environment(newOptions);
85
- }
73
+ return new this.constructor(newOptions);
74
+ };
86
75
 
87
- function assignVariables(newVars) {
88
- if (!newVars || typeof newVars !== 'object') return;
76
+ proto.assignVariables = function assignVariables(newVars) {
77
+ if (!newVars || typeof newVars !== 'object') return;
89
78
 
90
- variables = {
91
- ...variables,
92
- ...newVars,
93
- };
94
- }
79
+ this[variablesSymbol] = {
80
+ ...this.variables,
81
+ ...newVars,
82
+ };
83
+ };
95
84
 
96
- function getScript(...args) {
97
- return scripts.getScript(...args);
98
- }
85
+ proto.getScript = function getScript(...args) {
86
+ return this.scripts.getScript(...args);
87
+ };
99
88
 
100
- function registerScript(...args) {
101
- return scripts.register(...args);
102
- }
89
+ proto.registerScript = function registerScript(...args) {
90
+ return this.scripts.register(...args);
91
+ };
103
92
 
104
- function getServiceByName(serviceName) {
105
- return services[serviceName];
106
- }
93
+ proto.getServiceByName = function getServiceByName(serviceName) {
94
+ return this.services[serviceName];
95
+ };
107
96
 
108
- function resolveExpression(expression, message = {}, expressionFnContext) {
109
- const from = {
110
- environment: environmentApi,
111
- ...message,
112
- };
97
+ proto.resolveExpression = function resolveExpression(expression, message = {}, expressionFnContext) {
98
+ const from = {
99
+ environment: this,
100
+ ...message,
101
+ };
113
102
 
114
- return expressions.resolveExpression(expression, from, expressionFnContext);
115
- }
103
+ return this.expressions.resolveExpression(expression, from, expressionFnContext);
104
+ };
116
105
 
117
- function addService(name, fn) {
118
- services[name] = fn;
119
- }
120
- }
106
+ proto.addService = function addService(name, fn) {
107
+ this.services[name] = fn;
108
+ };
121
109
 
122
110
  function validateOptions(input) {
123
111
  const options = {};
@@ -23,7 +23,7 @@ function DefinitionBroker(owner, onBrokerReturn) {
23
23
  }
24
24
 
25
25
  function MessageFlowBroker(owner) {
26
- const eventBroker = EventBroker(owner, {prefix: 'messageflow', autoDelete: false, durable: false});
26
+ const eventBroker = new EventBroker(owner, {prefix: 'messageflow', autoDelete: false, durable: false});
27
27
  const broker = eventBroker.broker;
28
28
 
29
29
  broker.assertExchange('message', 'topic', {durable: true, autoDelete: false});
@@ -34,7 +34,7 @@ function MessageFlowBroker(owner) {
34
34
  }
35
35
 
36
36
  function ExecutionBroker(brokerOwner, prefix, onBrokerReturn) {
37
- const eventBroker = EventBroker(brokerOwner, {prefix, autoDelete: false, durable: false}, onBrokerReturn);
37
+ const eventBroker = new EventBroker(brokerOwner, {prefix, autoDelete: false, durable: false}, onBrokerReturn);
38
38
  const broker = eventBroker.broker;
39
39
 
40
40
  broker.assertExchange('api', 'topic', {autoDelete: false, durable: false});
@@ -54,90 +54,89 @@ function ExecutionBroker(brokerOwner, prefix, onBrokerReturn) {
54
54
  }
55
55
 
56
56
  function EventBroker(brokerOwner, options, onBrokerReturn) {
57
- const broker = Broker(brokerOwner);
58
- const pfx = options.prefix;
57
+ this.options = options;
58
+ this.eventPrefix = options.prefix;
59
59
 
60
+ const broker = this.broker = Broker(brokerOwner);
60
61
  broker.assertExchange('event', 'topic', options);
61
- broker.on('return', onBrokerReturn || onBrokerReturnFn);
62
+ broker.on('return', onBrokerReturn ? onBrokerReturn.bind(brokerOwner) : this._onBrokerReturnFn.bind(this));
62
63
 
63
- return {
64
- eventPrefix: pfx,
65
- broker,
66
- on,
67
- once,
68
- waitFor,
69
- emit,
70
- emitFatal,
71
- };
64
+ this.on = this.on.bind(this);
65
+ this.once = this.once.bind(this);
66
+ this.waitFor = this.waitFor.bind(this);
67
+ this.emit = this.emit.bind(this);
68
+ this.emitFatal = this.emitFatal.bind(this);
69
+ }
72
70
 
73
- function on(eventName, callback, eventOptions = { once: false }) {
74
- const key = getEventRoutingKey(eventName);
71
+ EventBroker.prototype.on = function on(eventName, callback, eventOptions = { once: false }) {
72
+ const key = this._getEventRoutingKey(eventName);
75
73
 
76
- if (eventOptions.once) return broker.subscribeOnce('event', key, eventCallback, eventOptions);
77
- return broker.subscribeTmp('event', key, eventCallback, {...eventOptions, noAck: true});
74
+ if (eventOptions.once) return this.broker.subscribeOnce('event', key, eventCallback, eventOptions);
75
+ return this.broker.subscribeTmp('event', key, eventCallback, {...eventOptions, noAck: true});
78
76
 
79
- function eventCallback(routingKey, message, owner) {
80
- if (eventName === 'error') return callback(makeErrorFromMessage(message));
81
- callback(owner.getApi(message));
82
- }
77
+ function eventCallback(routingKey, message, owner) {
78
+ if (eventName === 'error') return callback(makeErrorFromMessage(message));
79
+ callback(owner.getApi(message));
83
80
  }
81
+ };
84
82
 
85
- function once(eventName, callback, eventOptions = {}) {
86
- return on(eventName, callback, {...eventOptions, once: true});
87
- }
83
+ EventBroker.prototype.once = function once(eventName, callback, eventOptions = {}) {
84
+ return this.on(eventName, callback, {...eventOptions, once: true});
85
+ };
88
86
 
89
- function waitFor(eventName, onMessage) {
90
- const key = getEventRoutingKey(eventName);
87
+ EventBroker.prototype.waitFor = function waitFor(eventName, onMessage) {
88
+ const key = this._getEventRoutingKey(eventName);
91
89
 
92
- return new Promise((resolve, reject) => {
93
- const consumers = [
94
- broker.subscribeTmp('event', key, eventCallback, {noAck: true}),
95
- broker.subscribeTmp('event', '*.error', errorCallback, {noAck: true})
96
- ];
90
+ return new Promise((resolve, reject) => {
91
+ const consumers = [
92
+ this.broker.subscribeTmp('event', key, eventCallback, {noAck: true}),
93
+ this.broker.subscribeTmp('event', '*.error', errorCallback, {noAck: true})
94
+ ];
97
95
 
98
- function eventCallback(routingKey, message, owner) {
99
- if (onMessage && !onMessage(routingKey, message, owner)) return;
100
- unsubscribe();
101
- return resolve(owner.getApi(message));
102
- }
96
+ function eventCallback(routingKey, message, owner) {
97
+ if (onMessage && !onMessage(routingKey, message, owner)) return;
98
+ unsubscribe();
99
+ return resolve(owner.getApi(message));
100
+ }
103
101
 
104
- function errorCallback(routingKey, message, owner) {
105
- if (!message.properties.mandatory) return;
106
- unsubscribe();
107
- return reject(makeErrorFromMessage(message, owner));
108
- }
102
+ function errorCallback(routingKey, message, owner) {
103
+ if (!message.properties.mandatory) return;
104
+ unsubscribe();
105
+ return reject(makeErrorFromMessage(message, owner));
106
+ }
109
107
 
110
- function unsubscribe() {
111
- consumers.forEach((consumer) => consumer.cancel());
108
+ function unsubscribe() {
109
+ for (const consumer of consumers) {
110
+ consumer.cancel();
112
111
  }
113
- });
114
- }
115
-
116
- function onBrokerReturnFn(message) {
117
- if (message.properties.type === 'error') {
118
- const err = makeErrorFromMessage(message);
119
- throw err;
120
112
  }
121
- }
113
+ });
114
+ };
122
115
 
123
- function getEventRoutingKey(eventName) {
124
- if (eventName.indexOf('.') > -1) return eventName;
116
+ EventBroker.prototype.emit = function emit(eventName, content, props) {
117
+ this.broker.publish('event', `${this.eventPrefix}.${eventName}`, {...content}, {type: eventName, ...props});
118
+ };
125
119
 
126
- switch (eventName) {
127
- case 'wait': {
128
- return `activity.${eventName}`;
129
- }
130
- default: {
131
- return `${pfx}.${eventName}`;
132
- }
133
- }
134
- }
120
+ EventBroker.prototype.emitFatal = function emitFatal(error, content) {
121
+ this.emit('error', {...content, error}, {mandatory: true});
122
+ };
135
123
 
136
- function emit(eventName, content = {}, props = {}) {
137
- broker.publish('event', `${pfx}.${eventName}`, {...content}, {type: eventName, ...props});
124
+ EventBroker.prototype._onBrokerReturnFn = function onBrokerReturnFn(message) {
125
+ if (message.properties.type === 'error') {
126
+ const err = makeErrorFromMessage(message);
127
+ throw err;
138
128
  }
129
+ };
130
+
131
+ EventBroker.prototype._getEventRoutingKey = function getEventRoutingKey(eventName) {
132
+ if (eventName.indexOf('.') > -1) return eventName;
139
133
 
140
- function emitFatal(error, content = {}) {
141
- emit('error', {...content, error}, {mandatory: true});
134
+ switch (eventName) {
135
+ case 'wait': {
136
+ return `activity.${eventName}`;
137
+ }
138
+ default: {
139
+ return `${this.eventPrefix}.${eventName}`;
140
+ }
142
141
  }
143
- }
142
+ };
@@ -20,10 +20,10 @@ export default function ExtensionsMapper(context) {
20
20
  }
21
21
 
22
22
  function activate(message) {
23
- activityExtensions.forEach((extension) => extension.activate(message));
23
+ for (const extension of activityExtensions) extension.activate(message);
24
24
  }
25
25
  function deactivate(message) {
26
- activityExtensions.forEach((extension) => extension.deactivate(message));
26
+ for (const extension of activityExtensions) extension.deactivate(message);
27
27
  }
28
28
  }
29
29
 
@@ -1,96 +1,154 @@
1
- import {cloneMessage, cloneParent, cloneContent} from './messageHelper';
2
- import {filterUndefined} from './shared';
1
+ import {cloneMessage} from './messageHelper';
2
+ import {getUniqueId} from './shared';
3
3
  import {ActivityError} from './error/Errors';
4
4
  import {getRoutingKeyPattern} from 'smqp';
5
5
 
6
+ const onMessageSymbol = Symbol.for('onMessage');
7
+ const executionSymbol = Symbol.for('execution');
8
+
6
9
  export {Formatter};
7
10
 
8
11
  function Formatter(element, formatQ) {
9
12
  const {id, broker, logger} = element;
13
+ this.id = id;
14
+ this.broker = broker;
15
+ this.logger = logger;
16
+ this.formatQ = formatQ;
10
17
 
11
- return function formatRunMessage(runMessage, callback) {
12
- const startFormatMsg = formatQ.get();
13
- if (!startFormatMsg) return callback(null, runMessage.content, false);
14
-
15
- const pendingFormats = [];
16
- const {fields, content} = runMessage;
17
- const fundamentals = {
18
- id: content.id,
19
- type: content.type,
20
- parent: cloneParent(content.parent),
21
- attachedTo: content.attachedTo,
22
- executionId: content.executionId,
23
- isSubProcess: content.isSubProcess,
24
- isMultiInstance: content.isMultiInstance,
25
- };
26
- if (content.inbound) {
27
- fundamentals.inbound = content.inbound.slice();
28
- }
29
- if (content.outbound) {
30
- fundamentals.outbound = content.outbound.slice();
31
- }
32
-
33
- let formattingError;
34
- let formattedContent = cloneContent(content);
18
+ this.pendingFormats = [];
35
19
 
36
- const depleted = formatQ.on('depleted', () => {
37
- if (pendingFormats.length) return;
38
- depleted.cancel();
39
- logger.debug(`<${id}> completed formatting ${fields.routingKey}`);
40
- broker.cancel('_format-consumer');
41
- if (formattingError) return callback(formattingError);
42
- return callback(null, filterUndefined(formattedContent), true);
43
- });
20
+ this[onMessageSymbol] = this._onMessage.bind(this);
21
+ }
44
22
 
45
- startFormatMsg.nack(false, true);
46
- formatQ.assertConsumer(onFormatMessage, { consumerTag: '_format-consumer', prefetch: 100 });
23
+ Formatter.prototype.format = function format(message, callback) {
24
+ const correlationId = this._runId = getUniqueId(message.fields.routingKey);
25
+ const consumerTag = '_formatter-' + correlationId;
26
+ const formatQ = this.formatQ;
27
+
28
+ formatQ.queueMessage({
29
+ routingKey: '_formatting.exec',
30
+ }, {}, {
31
+ correlationId,
32
+ persistent: false,
33
+ });
34
+
35
+ this[executionSymbol] = {
36
+ correlationId,
37
+ formatKey: message.fields.routingKey,
38
+ runMessage: cloneMessage(message),
39
+ callback,
40
+ pending: [],
41
+ formatted: false,
42
+ executeMessage: null,
43
+ };
47
44
 
48
- function onFormatMessage(routingKey, message) {
49
- const {endRoutingKey, error} = message.content || {};
45
+ formatQ.consume(this[onMessageSymbol], {
46
+ consumerTag,
47
+ prefetch: 100,
48
+ });
49
+ };
50
+
51
+ Formatter.prototype._onMessage = function onMessage(routingKey, message) {
52
+ const {formatKey, correlationId, pending, executeMessage} = this[executionSymbol];
53
+ const asyncFormatting = pending.length;
54
+
55
+ switch (routingKey) {
56
+ case '_formatting.exec':
57
+ if (message.properties.correlationId !== correlationId) return message.ack();
58
+ if (!asyncFormatting) {
59
+ message.ack();
60
+ return this._complete(message);
61
+ }
62
+ this[executionSymbol].executeMessage = message;
63
+ break;
64
+ default: {
65
+ message.ack();
50
66
 
67
+ const endRoutingKey = message.content && message.content.endRoutingKey;
51
68
  if (endRoutingKey) {
52
- pendingFormats.push(message);
53
- return logger.debug(`<${id}> start formatting ${fields.routingKey} message content with formatter ${routingKey}`);
69
+ this._decorate(message.content);
70
+ pending.push(message);
71
+ return this._debug(`start formatting ${formatKey} message content with formatter ${routingKey}`);
54
72
  }
55
73
 
56
- const {isError, message: formatStart} = popFormattingStart(routingKey);
57
-
58
- logger.debug(`<${id}> format ${fields.routingKey} message content with formatter ${routingKey}`);
74
+ if (asyncFormatting) {
75
+ const {isError, message: startMessage} = this._popFormatStart(pending, routingKey);
76
+ if (startMessage) startMessage.ack();
59
77
 
60
- formattedContent = {
61
- ...formattedContent,
62
- ...message.content,
63
- ...fundamentals,
64
- };
65
-
66
- message.ack();
67
- if (formatStart) {
68
78
  if (isError) {
69
- const errMessage = error && error.message || 'formatting failed';
70
- logger.debug(`<${id}> formatting of ${fields.routingKey} failed with ${routingKey}: ${errMessage}`);
71
- formattingError = new ActivityError(errMessage, cloneMessage(runMessage, formattedContent), error);
72
- pendingFormats.splice(0).forEach(({nack}) => nack(false, false));
79
+ return this._complete(message, true);
73
80
  }
74
- formatStart.ack(isError);
75
81
  }
76
- }
77
82
 
78
- function popFormattingStart(routingKey) {
79
- for (let i = 0; i < pendingFormats.length; i++) {
80
- const pendingFormat = pendingFormats[i];
81
- const {endRoutingKey, errorRoutingKey = '#.error'} = pendingFormat.content;
82
-
83
- if (getRoutingKeyPattern(endRoutingKey).test(routingKey)) {
84
- logger.debug(`<${id}> completed formatting ${fields.routingKey} message content with formatter ${routingKey}`);
85
- pendingFormats.splice(i, 1);
86
- return {message: pendingFormat};
87
- } else if (getRoutingKeyPattern(errorRoutingKey).test(routingKey)) {
88
- pendingFormats.splice(i, 1);
89
- return {isError: true, message: pendingFormat};
90
- }
91
- }
83
+ this._decorate(message.content);
84
+ this._debug(`format ${message.fields.routingKey} message content with formatter ${routingKey}`);
92
85
 
93
- return {};
86
+ if (executeMessage && asyncFormatting && !pending.length) {
87
+ this._complete(message);
88
+ }
94
89
  }
95
- };
96
- }
90
+ }
91
+ };
92
+
93
+ Formatter.prototype._complete = function complete(message, isError) {
94
+ const {runMessage, formatKey, callback, formatted, executeMessage} = this[executionSymbol];
95
+ this[executionSymbol] = null;
96
+ if (executeMessage) executeMessage.ack();
97
+
98
+ this.broker.cancel(message.fields.consumerTag);
99
+
100
+ if (isError) {
101
+ const error = (message.content && message.content.error) || new Error('formatting failed');
102
+ const errMessage = error.message || 'formatting failed';
103
+ this._debug(`formatting of ${formatKey} failed with ${message.fields.routingKey}: ${errMessage}`);
104
+ return callback(new ActivityError(errMessage, cloneMessage(runMessage), error));
105
+ }
106
+
107
+ return callback(null, runMessage.content, formatted);
108
+ };
109
+
110
+ Formatter.prototype._decorate = function decorate(withContent) {
111
+ const content = this[executionSymbol].runMessage.content;
112
+ for (const key in withContent) {
113
+ switch (key) {
114
+ case 'id':
115
+ case 'type':
116
+ case 'parent':
117
+ case 'attachedTo':
118
+ case 'executionId':
119
+ case 'isSubProcess':
120
+ case 'isMultiInstance':
121
+ case 'inbound':
122
+ case 'outbound':
123
+ case 'endRoutingKey':
124
+ case 'errorRoutingKey':
125
+ break;
126
+ default: {
127
+ content[key] = withContent[key];
128
+ this[executionSymbol].formatted = true;
129
+ }
130
+ }
131
+ }
132
+ };
133
+
134
+ Formatter.prototype._popFormatStart = function popFormattingStart(pending, routingKey) {
135
+ for (let idx = 0; idx < pending.length; idx++) {
136
+ const msg = pending[idx];
137
+ const {endRoutingKey, errorRoutingKey = '#.error'} = msg.content;
138
+
139
+ if (endRoutingKey && getRoutingKeyPattern(endRoutingKey).test(routingKey)) {
140
+ this._debug(`completed formatting ${msg.fields.routingKey} message content with formatter ${routingKey}`);
141
+ pending.splice(idx, 1);
142
+ return {message: msg};
143
+ } else if (getRoutingKeyPattern(errorRoutingKey).test(routingKey)) {
144
+ pending.splice(idx, 1);
145
+ return {isError: true, message: msg};
146
+ }
147
+ }
148
+
149
+ return {};
150
+ };
151
+
152
+ Formatter.prototype._debug = function debug(msg) {
153
+ this.logger.debug(`<${this.id}> ${msg}`);
154
+ };
package/src/Timers.js CHANGED
@@ -35,7 +35,7 @@ export function Timers(options) {
35
35
  function wrappedSetTimeout(callback, delay, ...args) {
36
36
  const ref = {timerId: `timer_${count++}`, callback, delay, args, owner: this};
37
37
  executing.push(ref);
38
- ref.timerRef = options.setTimeout.call(this, onTimeout, delay, ...args);
38
+ ref.timerRef = options.setTimeout.call(null, onTimeout, delay, ...args);
39
39
  return ref;
40
40
 
41
41
  function onTimeout(...rargs) {
@@ -48,9 +48,9 @@ export function Timers(options) {
48
48
  function wrappedClearTimeout(ref) {
49
49
  const idx = executing.indexOf(ref);
50
50
  if (idx > -1) {
51
- const [{owner}] = executing.splice(idx, 1);
52
- return options.clearTimeout.call(owner, ref.timerRef);
51
+ executing.splice(idx, 1);
52
+ return options.clearTimeout.call(null, ref.timerRef);
53
53
  }
54
- return options.clearTimeout(ref);
54
+ return options.clearTimeout.call(null, ref);
55
55
  }
56
56
  }