@ti-engine/core 1.7.1 → 1.8.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.
- package/CHANGELOG.md +393 -377
- package/LICENSE.md +321 -321
- package/README.md +599 -597
- package/bin/localization/labels.json +122 -122
- package/bin/settings.json +41 -41
- package/bin/start-instance.js +164 -164
- package/components/auditing.js +191 -191
- package/components/connection-observer.js +72 -72
- package/components/definitions.types.js +248 -248
- package/components/exchange/default/default-message-exchange.js +136 -136
- package/components/exchange/default/default-message-receiver.js +101 -101
- package/components/exchange/default/default-message-sender.js +100 -100
- package/components/exchange/message-dispatcher.js +168 -168
- package/components/exchange/message-exchange.js +449 -449
- package/components/exchange/message-handler.js +235 -235
- package/components/exchange/message-memory-cache.js +190 -190
- package/components/exchange/message-observer.js +126 -126
- package/components/exchange/message-receiver.js +181 -181
- package/components/exchange/message-sender.js +143 -143
- package/components/exchange/message-tracer.js +212 -212
- package/components/service-caller.js +370 -370
- package/components/service-consumer.js +131 -131
- package/components/service-executor.js +278 -278
- package/components/service-instance.js +316 -316
- package/components/service-provider.js +251 -251
- package/integrations/redis-integration.js +591 -591
- package/package.json +89 -89
- package/utils/cache.js +772 -772
- package/utils/config.js +103 -103
- package/utils/exceptions.js +368 -368
- package/utils/localization.js +298 -298
- package/utils/logger.js +82 -82
- package/utils/tools.js +632 -632
|
@@ -1,450 +1,450 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.
|
|
3
|
-
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
|
-
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
5
|
-
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
6
|
-
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const MessageObserver = require( "#message-observer" );
|
|
10
|
-
const _ = require( "lodash" );
|
|
11
|
-
const exceptions = require( "#exceptions" );
|
|
12
|
-
const messageTracer = require( "#message-tracer" );
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* An abstract class that defines a message exchange behavior.
|
|
16
|
-
* <br/>
|
|
17
|
-
* NOTE: While this sets the basis frame for the message-based communication between microservices, it has to be inherited and
|
|
18
|
-
* extended with additional logic that is NOT implemented here. For a working example please see {@link DefaultMessageExchange} class.
|
|
19
|
-
* <br/>
|
|
20
|
-
* NOTE: This class and its children are designed to be used internally by the {@link MessageDispatcher} and its related classes.
|
|
21
|
-
*
|
|
22
|
-
* @class MessageExchange
|
|
23
|
-
* @extends MessageObserver
|
|
24
|
-
* @abstract
|
|
25
|
-
* @public
|
|
26
|
-
*/
|
|
27
|
-
class MessageExchange extends MessageObserver {
|
|
28
|
-
|
|
29
|
-
static #connectionNameRequestsOut = "connection-msg-requests-out";
|
|
30
|
-
static #connectionNameRequestsIn = "connection-msg-requests-in";
|
|
31
|
-
static #connectionNameResponsesOut = "connection-msg-responses-out";
|
|
32
|
-
static #connectionNameResponsesIn = "connection-msg-responses-in";
|
|
33
|
-
#instanceID;
|
|
34
|
-
#serviceDomainName;
|
|
35
|
-
#disruptedConnections;
|
|
36
|
-
#configuredOutbound = false;
|
|
37
|
-
#configuredInbound = false;
|
|
38
|
-
/** @type MessageSender */
|
|
39
|
-
#messageRequestsOut;
|
|
40
|
-
/** @type MessageSender */
|
|
41
|
-
#messageResponsesOut;
|
|
42
|
-
/** @type MessageReceiver */
|
|
43
|
-
#messageRequestsIn;
|
|
44
|
-
/** @type MessageReceiver */
|
|
45
|
-
#messageResponsesIn;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @constructor
|
|
49
|
-
* @param {string} instanceID The unique identifier of the microservice instance using the message exchange.
|
|
50
|
-
* @param {string} serviceDomainName The domain name of the microservice using the message exchange.
|
|
51
|
-
* @throws {TiException.E_GEN_ABSTRACT_CLASS_INIT} If this class is instantiated directly.
|
|
52
|
-
*/
|
|
53
|
-
constructor( instanceID, serviceDomainName ) {
|
|
54
|
-
super( 9 );
|
|
55
|
-
|
|
56
|
-
// make sure this abstract class cannot be instantiated:
|
|
57
|
-
if ( new.target === MessageExchange ) {
|
|
58
|
-
throw exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_CLASS_INIT, { name: this.constructor.name } );
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
this.#instanceID = instanceID;
|
|
62
|
-
this.#serviceDomainName = serviceDomainName;
|
|
63
|
-
this.#disruptedConnections = [];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/* Public interface */
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Property returning the configured connection name for the outgoing message requests.
|
|
70
|
-
*
|
|
71
|
-
* @property
|
|
72
|
-
* @returns {string}
|
|
73
|
-
* @public
|
|
74
|
-
*/
|
|
75
|
-
static get connectionNameRequestsOut() {
|
|
76
|
-
return this.#connectionNameRequestsOut;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Used to set the connection name for the outgoing message requests.
|
|
81
|
-
*
|
|
82
|
-
* @property
|
|
83
|
-
* @param {string} value
|
|
84
|
-
* @public
|
|
85
|
-
*/
|
|
86
|
-
static set connectionNameRequestsOut( value ) {
|
|
87
|
-
this.#connectionNameRequestsOut = value;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Property returning the configured connection name for the incoming message requests.
|
|
92
|
-
*
|
|
93
|
-
* @property
|
|
94
|
-
* @returns {string}
|
|
95
|
-
* @public
|
|
96
|
-
*/
|
|
97
|
-
static get connectionNameRequestsIn() {
|
|
98
|
-
return this.#connectionNameRequestsIn;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Used to set the connection name for the incoming message requests.
|
|
103
|
-
*
|
|
104
|
-
* @property
|
|
105
|
-
* @param {string} value
|
|
106
|
-
* @public
|
|
107
|
-
*/
|
|
108
|
-
static set connectionNameRequestsIn( value ) {
|
|
109
|
-
this.#connectionNameRequestsIn = value;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Property returning the configured connection name for the outgoing message responses.
|
|
114
|
-
*
|
|
115
|
-
* @property
|
|
116
|
-
* @returns {string}
|
|
117
|
-
* @public
|
|
118
|
-
*/
|
|
119
|
-
static get connectionNameResponsesOut() {
|
|
120
|
-
return this.#connectionNameResponsesOut;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Used to set the connection name for the outgoing message responses.
|
|
125
|
-
*
|
|
126
|
-
* @property
|
|
127
|
-
* @param {string} value
|
|
128
|
-
* @public
|
|
129
|
-
*/
|
|
130
|
-
static set connectionNameResponsesOut( value ) {
|
|
131
|
-
this.#connectionNameResponsesOut = value;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Property returning the configured connection name for the incoming message responses.
|
|
136
|
-
*
|
|
137
|
-
* @property
|
|
138
|
-
* @returns {string}
|
|
139
|
-
* @public
|
|
140
|
-
*/
|
|
141
|
-
static get connectionNameResponsesIn() {
|
|
142
|
-
return this.#connectionNameResponsesIn;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Used to set the connection name for the incoming message responses.
|
|
147
|
-
*
|
|
148
|
-
* @property
|
|
149
|
-
* @param {string} value
|
|
150
|
-
* @public
|
|
151
|
-
*/
|
|
152
|
-
static set connectionNameResponsesIn( value ) {
|
|
153
|
-
this.#connectionNameResponsesIn = value;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Property returning the identifier of the pending messages queue.
|
|
158
|
-
*
|
|
159
|
-
* @property
|
|
160
|
-
* @returns {string}
|
|
161
|
-
* @public
|
|
162
|
-
*/
|
|
163
|
-
static get pendingQueue() {
|
|
164
|
-
return "pending:";
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Property returning the identifier of the processed messages queue.
|
|
169
|
-
*
|
|
170
|
-
* @property
|
|
171
|
-
* @returns {string}
|
|
172
|
-
* @public
|
|
173
|
-
*/
|
|
174
|
-
static get processedQueue() {
|
|
175
|
-
return "processed:";
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Property returning the configured service instance ID.
|
|
180
|
-
*
|
|
181
|
-
* @property
|
|
182
|
-
* @returns {string}
|
|
183
|
-
* @public
|
|
184
|
-
*/
|
|
185
|
-
get instanceID() {
|
|
186
|
-
return this.#instanceID;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Property returning the configured service domain name.
|
|
191
|
-
*
|
|
192
|
-
* @property
|
|
193
|
-
* @returns {string}
|
|
194
|
-
* @public
|
|
195
|
-
*/
|
|
196
|
-
get serviceDomainName() {
|
|
197
|
-
return this.#serviceDomainName;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Returns the currently configured {@link MessageSender} for outbound message requests.
|
|
202
|
-
*
|
|
203
|
-
* @property
|
|
204
|
-
* @returns {MessageSender}
|
|
205
|
-
* @public
|
|
206
|
-
*/
|
|
207
|
-
get messageRequestsOut() {
|
|
208
|
-
return this.#messageRequestsOut;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Returns the currently configured {@link MessageSender} for outbound message responses.
|
|
213
|
-
*
|
|
214
|
-
* @property
|
|
215
|
-
* @returns {MessageSender}
|
|
216
|
-
* @public
|
|
217
|
-
*/
|
|
218
|
-
get messageResponsesOut() {
|
|
219
|
-
return this.#messageResponsesOut;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Returns the currently configured {@link MessageReceiver} for inbound message requests.
|
|
224
|
-
*
|
|
225
|
-
* @property
|
|
226
|
-
* @returns {MessageReceiver}
|
|
227
|
-
* @public
|
|
228
|
-
*/
|
|
229
|
-
get messageRequestsIn() {
|
|
230
|
-
return this.#messageRequestsIn;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Returns the currently configured {@link MessageReceiver} for inbound message responses.
|
|
235
|
-
*
|
|
236
|
-
* @property
|
|
237
|
-
* @returns {MessageReceiver}
|
|
238
|
-
* @public
|
|
239
|
-
*/
|
|
240
|
-
get messageResponsesIn() {
|
|
241
|
-
return this.#messageResponsesIn;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Returns a flag indicating if the message exchange is configured for outbound communication.
|
|
246
|
-
*
|
|
247
|
-
* @property
|
|
248
|
-
* @returns {boolean}
|
|
249
|
-
* @public
|
|
250
|
-
*/
|
|
251
|
-
get configuredOutbound() {
|
|
252
|
-
return this.#configuredOutbound;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Returns a flag indicating if the message exchange is configured for inbound communication.
|
|
257
|
-
*
|
|
258
|
-
* @property
|
|
259
|
-
* @returns {boolean}
|
|
260
|
-
* @public
|
|
261
|
-
*/
|
|
262
|
-
get configuredInbound() {
|
|
263
|
-
return this.#configuredInbound;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Should be used to enable all communication channels for messaging.
|
|
268
|
-
* <br/>
|
|
269
|
-
* NOTE: Override this to implement messaging initialization.
|
|
270
|
-
*
|
|
271
|
-
* @method
|
|
272
|
-
* @param {boolean} configureInbound If set to 'true' it tells the message exchange to set up inbound messaging.
|
|
273
|
-
* @param {boolean} configureOutbound If set to 'true' it tells the message exchange to set up outbound messaging.
|
|
274
|
-
* @returns {Promise}
|
|
275
|
-
* @abstract
|
|
276
|
-
* @public
|
|
277
|
-
*/
|
|
278
|
-
enableMessaging( configureInbound, configureOutbound ) {
|
|
279
|
-
return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.enableMessaging.name } ) );
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Should be used to gracefully disable all communication channels for messaging.
|
|
284
|
-
* <br/>
|
|
285
|
-
* NOTE: Override this to implement graceful messaging shut down.
|
|
286
|
-
*
|
|
287
|
-
* @method
|
|
288
|
-
* @returns {Promise}
|
|
289
|
-
* @abstract
|
|
290
|
-
* @public
|
|
291
|
-
*/
|
|
292
|
-
disableMessaging() {
|
|
293
|
-
return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.disableMessaging.name } ) );
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Used to configure the message exchange for receiving inbound messages and returning responses to them.
|
|
298
|
-
* Should typically be called from an implemented {@link enableMessaging} method.
|
|
299
|
-
*
|
|
300
|
-
* @method
|
|
301
|
-
* @param {MessageReceiver} messageReceiverRequestsIn A message receiver that will handle the inbound messages.
|
|
302
|
-
* @param {MessageSender} messageSenderResponsesOut A message sender that will handle the sending of responses for the inbound messages.
|
|
303
|
-
* @public
|
|
304
|
-
*/
|
|
305
|
-
configureInboundMessaging( messageReceiverRequestsIn, messageSenderResponsesOut ) {
|
|
306
|
-
this.#messageRequestsIn = messageReceiverRequestsIn;
|
|
307
|
-
this.#messageResponsesOut = messageSenderResponsesOut;
|
|
308
|
-
this.#configuredInbound = true;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Used to configure message exchange for sending messages and receiving responses to them.
|
|
313
|
-
* Should typically be called from an implemented {@link enableMessaging} method.
|
|
314
|
-
*
|
|
315
|
-
* @method
|
|
316
|
-
* @param {MessageSender} messageSenderRequestsOut A message sender that will handle the outbound messages.
|
|
317
|
-
* @param {MessageReceiver} messageReceiverResponsesIn A message receiver that will handle the returned responses for the outbound messages.
|
|
318
|
-
* @public
|
|
319
|
-
*/
|
|
320
|
-
configureOutboundMessaging( messageSenderRequestsOut, messageReceiverResponsesIn ) {
|
|
321
|
-
this.#messageRequestsOut = messageSenderRequestsOut;
|
|
322
|
-
this.#messageResponsesIn = messageReceiverResponsesIn;
|
|
323
|
-
this.#configuredOutbound = true;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Used to add an additional {@link MessageObserver} to the connection for the incoming message requests.
|
|
328
|
-
*
|
|
329
|
-
* @method
|
|
330
|
-
* @param {MessageObserver} messageObserver
|
|
331
|
-
* @public
|
|
332
|
-
*/
|
|
333
|
-
addMessageObserverRequestsIn( messageObserver ) {
|
|
334
|
-
this.#messageRequestsIn.addMessageObserver( messageObserver );
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Used to add an additional {@link MessageObserver} to the connection for the incoming message responses.
|
|
339
|
-
*
|
|
340
|
-
* @method
|
|
341
|
-
* @param {MessageObserver} messageObserver
|
|
342
|
-
* @public
|
|
343
|
-
*/
|
|
344
|
-
addMessageObserverResponsesIn( messageObserver ) {
|
|
345
|
-
this.#messageResponsesIn.addMessageObserver( messageObserver );
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Used to mark the connection with the provided identifier as disrupted.
|
|
350
|
-
*
|
|
351
|
-
* @method
|
|
352
|
-
* @param {string} identifier The identifier of the observed connection.
|
|
353
|
-
* @override
|
|
354
|
-
* @public
|
|
355
|
-
*/
|
|
356
|
-
onConnectionDisrupted( identifier ) {
|
|
357
|
-
this.#disruptedConnections.push( identifier );
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Used to mark the connection with the provided identifier as recovered.
|
|
362
|
-
* <br/>
|
|
363
|
-
* NOTE: This will also result in enabling the message exchange if no connections are currently disrupted.
|
|
364
|
-
*
|
|
365
|
-
* @method
|
|
366
|
-
* @param {string} identifier The identifier of the observed connection.
|
|
367
|
-
* @override
|
|
368
|
-
* @public
|
|
369
|
-
*/
|
|
370
|
-
onConnectionRecovered( identifier ) {
|
|
371
|
-
_.pull( this.#disruptedConnections, identifier );
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* Used to mark the connection with the provided identifier as disrupted.
|
|
376
|
-
*
|
|
377
|
-
* @method
|
|
378
|
-
* @param {string} identifier The identifier of the observed connection.
|
|
379
|
-
* @override
|
|
380
|
-
* @public
|
|
381
|
-
*/
|
|
382
|
-
onConnectionLost( identifier ) {
|
|
383
|
-
// TODO: implement triggering of a graceful shutdown of the service instance
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Used only for the message tracer.
|
|
388
|
-
*
|
|
389
|
-
* @method
|
|
390
|
-
* @param {string} identifier The identifier of the observed connection.
|
|
391
|
-
* @param {Message} message The message for processing.
|
|
392
|
-
* @returns {Message} The message that was received.
|
|
393
|
-
* @override
|
|
394
|
-
* @public
|
|
395
|
-
*/
|
|
396
|
-
onMessage( identifier, message ) {
|
|
397
|
-
message.destination.instanceID = this.#instanceID;
|
|
398
|
-
|
|
399
|
-
if ( MessageExchange.connectionNameRequestsIn === identifier ) {
|
|
400
|
-
messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_REQUEST, messageTracer.dispatchEvent.RECEIVED, messageTracer.messageState.PENDING );
|
|
401
|
-
} else if ( MessageExchange.connectionNameResponsesIn === identifier ) {
|
|
402
|
-
messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_RESPONSE, messageTracer.dispatchEvent.RECEIVED, messageTracer.messageState.PROCESSED );
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
return message;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* Used to check whether the connection with the provided identifier is currently in recovery mode.
|
|
410
|
-
*
|
|
411
|
-
* @method
|
|
412
|
-
* @param {string} identifier The identifier of the connection.
|
|
413
|
-
* @returns {boolean} Will return 'true' if the connection is currently disrupted and not yet recovered.
|
|
414
|
-
* @public
|
|
415
|
-
*/
|
|
416
|
-
isConnectionInRecovery( identifier ) {
|
|
417
|
-
return this.#disruptedConnections.indexOf( identifier ) !== -1;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Used to send a message request. Override of this method assumes that the message itself contains enough
|
|
422
|
-
* information to determine the sending destination.
|
|
423
|
-
*
|
|
424
|
-
* @method
|
|
425
|
-
* @param {Message} message The message request to send.
|
|
426
|
-
* @returns {Promise}
|
|
427
|
-
* @abstract
|
|
428
|
-
* @public
|
|
429
|
-
*/
|
|
430
|
-
sendMessageRequest( message ) {
|
|
431
|
-
return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.sendMessageRequest.name } ) );
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* Used to send a message response. Override of this method assumes that the message itself contains enough
|
|
436
|
-
* information to determine the sending destination.
|
|
437
|
-
*
|
|
438
|
-
* @method
|
|
439
|
-
* @param {Message} message The message response to send.
|
|
440
|
-
* @returns {Promise}
|
|
441
|
-
* @abstract
|
|
442
|
-
* @public
|
|
443
|
-
*/
|
|
444
|
-
sendMessageResponse( message ) {
|
|
445
|
-
return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.sendMessageResponse.name } ) );
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
}
|
|
449
|
-
|
|
1
|
+
/*
|
|
2
|
+
* The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.
|
|
3
|
+
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
|
+
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
5
|
+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
6
|
+
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const MessageObserver = require( "#message-observer" );
|
|
10
|
+
const _ = require( "lodash" );
|
|
11
|
+
const exceptions = require( "#exceptions" );
|
|
12
|
+
const messageTracer = require( "#message-tracer" );
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* An abstract class that defines a message exchange behavior.
|
|
16
|
+
* <br/>
|
|
17
|
+
* NOTE: While this sets the basis frame for the message-based communication between microservices, it has to be inherited and
|
|
18
|
+
* extended with additional logic that is NOT implemented here. For a working example please see {@link DefaultMessageExchange} class.
|
|
19
|
+
* <br/>
|
|
20
|
+
* NOTE: This class and its children are designed to be used internally by the {@link MessageDispatcher} and its related classes.
|
|
21
|
+
*
|
|
22
|
+
* @class MessageExchange
|
|
23
|
+
* @extends MessageObserver
|
|
24
|
+
* @abstract
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
class MessageExchange extends MessageObserver {
|
|
28
|
+
|
|
29
|
+
static #connectionNameRequestsOut = "connection-msg-requests-out";
|
|
30
|
+
static #connectionNameRequestsIn = "connection-msg-requests-in";
|
|
31
|
+
static #connectionNameResponsesOut = "connection-msg-responses-out";
|
|
32
|
+
static #connectionNameResponsesIn = "connection-msg-responses-in";
|
|
33
|
+
#instanceID;
|
|
34
|
+
#serviceDomainName;
|
|
35
|
+
#disruptedConnections;
|
|
36
|
+
#configuredOutbound = false;
|
|
37
|
+
#configuredInbound = false;
|
|
38
|
+
/** @type MessageSender */
|
|
39
|
+
#messageRequestsOut;
|
|
40
|
+
/** @type MessageSender */
|
|
41
|
+
#messageResponsesOut;
|
|
42
|
+
/** @type MessageReceiver */
|
|
43
|
+
#messageRequestsIn;
|
|
44
|
+
/** @type MessageReceiver */
|
|
45
|
+
#messageResponsesIn;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @constructor
|
|
49
|
+
* @param {string} instanceID The unique identifier of the microservice instance using the message exchange.
|
|
50
|
+
* @param {string} serviceDomainName The domain name of the microservice using the message exchange.
|
|
51
|
+
* @throws {TiException.E_GEN_ABSTRACT_CLASS_INIT} If this class is instantiated directly.
|
|
52
|
+
*/
|
|
53
|
+
constructor( instanceID, serviceDomainName ) {
|
|
54
|
+
super( 9 );
|
|
55
|
+
|
|
56
|
+
// make sure this abstract class cannot be instantiated:
|
|
57
|
+
if ( new.target === MessageExchange ) {
|
|
58
|
+
throw exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_CLASS_INIT, { name: this.constructor.name } );
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.#instanceID = instanceID;
|
|
62
|
+
this.#serviceDomainName = serviceDomainName;
|
|
63
|
+
this.#disruptedConnections = [];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Public interface */
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Property returning the configured connection name for the outgoing message requests.
|
|
70
|
+
*
|
|
71
|
+
* @property
|
|
72
|
+
* @returns {string}
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
static get connectionNameRequestsOut() {
|
|
76
|
+
return this.#connectionNameRequestsOut;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Used to set the connection name for the outgoing message requests.
|
|
81
|
+
*
|
|
82
|
+
* @property
|
|
83
|
+
* @param {string} value
|
|
84
|
+
* @public
|
|
85
|
+
*/
|
|
86
|
+
static set connectionNameRequestsOut( value ) {
|
|
87
|
+
this.#connectionNameRequestsOut = value;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Property returning the configured connection name for the incoming message requests.
|
|
92
|
+
*
|
|
93
|
+
* @property
|
|
94
|
+
* @returns {string}
|
|
95
|
+
* @public
|
|
96
|
+
*/
|
|
97
|
+
static get connectionNameRequestsIn() {
|
|
98
|
+
return this.#connectionNameRequestsIn;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Used to set the connection name for the incoming message requests.
|
|
103
|
+
*
|
|
104
|
+
* @property
|
|
105
|
+
* @param {string} value
|
|
106
|
+
* @public
|
|
107
|
+
*/
|
|
108
|
+
static set connectionNameRequestsIn( value ) {
|
|
109
|
+
this.#connectionNameRequestsIn = value;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Property returning the configured connection name for the outgoing message responses.
|
|
114
|
+
*
|
|
115
|
+
* @property
|
|
116
|
+
* @returns {string}
|
|
117
|
+
* @public
|
|
118
|
+
*/
|
|
119
|
+
static get connectionNameResponsesOut() {
|
|
120
|
+
return this.#connectionNameResponsesOut;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Used to set the connection name for the outgoing message responses.
|
|
125
|
+
*
|
|
126
|
+
* @property
|
|
127
|
+
* @param {string} value
|
|
128
|
+
* @public
|
|
129
|
+
*/
|
|
130
|
+
static set connectionNameResponsesOut( value ) {
|
|
131
|
+
this.#connectionNameResponsesOut = value;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Property returning the configured connection name for the incoming message responses.
|
|
136
|
+
*
|
|
137
|
+
* @property
|
|
138
|
+
* @returns {string}
|
|
139
|
+
* @public
|
|
140
|
+
*/
|
|
141
|
+
static get connectionNameResponsesIn() {
|
|
142
|
+
return this.#connectionNameResponsesIn;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Used to set the connection name for the incoming message responses.
|
|
147
|
+
*
|
|
148
|
+
* @property
|
|
149
|
+
* @param {string} value
|
|
150
|
+
* @public
|
|
151
|
+
*/
|
|
152
|
+
static set connectionNameResponsesIn( value ) {
|
|
153
|
+
this.#connectionNameResponsesIn = value;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Property returning the identifier of the pending messages queue.
|
|
158
|
+
*
|
|
159
|
+
* @property
|
|
160
|
+
* @returns {string}
|
|
161
|
+
* @public
|
|
162
|
+
*/
|
|
163
|
+
static get pendingQueue() {
|
|
164
|
+
return "pending:";
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Property returning the identifier of the processed messages queue.
|
|
169
|
+
*
|
|
170
|
+
* @property
|
|
171
|
+
* @returns {string}
|
|
172
|
+
* @public
|
|
173
|
+
*/
|
|
174
|
+
static get processedQueue() {
|
|
175
|
+
return "processed:";
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Property returning the configured service instance ID.
|
|
180
|
+
*
|
|
181
|
+
* @property
|
|
182
|
+
* @returns {string}
|
|
183
|
+
* @public
|
|
184
|
+
*/
|
|
185
|
+
get instanceID() {
|
|
186
|
+
return this.#instanceID;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Property returning the configured service domain name.
|
|
191
|
+
*
|
|
192
|
+
* @property
|
|
193
|
+
* @returns {string}
|
|
194
|
+
* @public
|
|
195
|
+
*/
|
|
196
|
+
get serviceDomainName() {
|
|
197
|
+
return this.#serviceDomainName;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Returns the currently configured {@link MessageSender} for outbound message requests.
|
|
202
|
+
*
|
|
203
|
+
* @property
|
|
204
|
+
* @returns {MessageSender}
|
|
205
|
+
* @public
|
|
206
|
+
*/
|
|
207
|
+
get messageRequestsOut() {
|
|
208
|
+
return this.#messageRequestsOut;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Returns the currently configured {@link MessageSender} for outbound message responses.
|
|
213
|
+
*
|
|
214
|
+
* @property
|
|
215
|
+
* @returns {MessageSender}
|
|
216
|
+
* @public
|
|
217
|
+
*/
|
|
218
|
+
get messageResponsesOut() {
|
|
219
|
+
return this.#messageResponsesOut;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Returns the currently configured {@link MessageReceiver} for inbound message requests.
|
|
224
|
+
*
|
|
225
|
+
* @property
|
|
226
|
+
* @returns {MessageReceiver}
|
|
227
|
+
* @public
|
|
228
|
+
*/
|
|
229
|
+
get messageRequestsIn() {
|
|
230
|
+
return this.#messageRequestsIn;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Returns the currently configured {@link MessageReceiver} for inbound message responses.
|
|
235
|
+
*
|
|
236
|
+
* @property
|
|
237
|
+
* @returns {MessageReceiver}
|
|
238
|
+
* @public
|
|
239
|
+
*/
|
|
240
|
+
get messageResponsesIn() {
|
|
241
|
+
return this.#messageResponsesIn;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Returns a flag indicating if the message exchange is configured for outbound communication.
|
|
246
|
+
*
|
|
247
|
+
* @property
|
|
248
|
+
* @returns {boolean}
|
|
249
|
+
* @public
|
|
250
|
+
*/
|
|
251
|
+
get configuredOutbound() {
|
|
252
|
+
return this.#configuredOutbound;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Returns a flag indicating if the message exchange is configured for inbound communication.
|
|
257
|
+
*
|
|
258
|
+
* @property
|
|
259
|
+
* @returns {boolean}
|
|
260
|
+
* @public
|
|
261
|
+
*/
|
|
262
|
+
get configuredInbound() {
|
|
263
|
+
return this.#configuredInbound;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Should be used to enable all communication channels for messaging.
|
|
268
|
+
* <br/>
|
|
269
|
+
* NOTE: Override this to implement messaging initialization.
|
|
270
|
+
*
|
|
271
|
+
* @method
|
|
272
|
+
* @param {boolean} configureInbound If set to 'true' it tells the message exchange to set up inbound messaging.
|
|
273
|
+
* @param {boolean} configureOutbound If set to 'true' it tells the message exchange to set up outbound messaging.
|
|
274
|
+
* @returns {Promise}
|
|
275
|
+
* @abstract
|
|
276
|
+
* @public
|
|
277
|
+
*/
|
|
278
|
+
enableMessaging( configureInbound, configureOutbound ) {
|
|
279
|
+
return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.enableMessaging.name } ) );
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Should be used to gracefully disable all communication channels for messaging.
|
|
284
|
+
* <br/>
|
|
285
|
+
* NOTE: Override this to implement graceful messaging shut down.
|
|
286
|
+
*
|
|
287
|
+
* @method
|
|
288
|
+
* @returns {Promise}
|
|
289
|
+
* @abstract
|
|
290
|
+
* @public
|
|
291
|
+
*/
|
|
292
|
+
disableMessaging() {
|
|
293
|
+
return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.disableMessaging.name } ) );
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Used to configure the message exchange for receiving inbound messages and returning responses to them.
|
|
298
|
+
* Should typically be called from an implemented {@link enableMessaging} method.
|
|
299
|
+
*
|
|
300
|
+
* @method
|
|
301
|
+
* @param {MessageReceiver} messageReceiverRequestsIn A message receiver that will handle the inbound messages.
|
|
302
|
+
* @param {MessageSender} messageSenderResponsesOut A message sender that will handle the sending of responses for the inbound messages.
|
|
303
|
+
* @public
|
|
304
|
+
*/
|
|
305
|
+
configureInboundMessaging( messageReceiverRequestsIn, messageSenderResponsesOut ) {
|
|
306
|
+
this.#messageRequestsIn = messageReceiverRequestsIn;
|
|
307
|
+
this.#messageResponsesOut = messageSenderResponsesOut;
|
|
308
|
+
this.#configuredInbound = true;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Used to configure message exchange for sending messages and receiving responses to them.
|
|
313
|
+
* Should typically be called from an implemented {@link enableMessaging} method.
|
|
314
|
+
*
|
|
315
|
+
* @method
|
|
316
|
+
* @param {MessageSender} messageSenderRequestsOut A message sender that will handle the outbound messages.
|
|
317
|
+
* @param {MessageReceiver} messageReceiverResponsesIn A message receiver that will handle the returned responses for the outbound messages.
|
|
318
|
+
* @public
|
|
319
|
+
*/
|
|
320
|
+
configureOutboundMessaging( messageSenderRequestsOut, messageReceiverResponsesIn ) {
|
|
321
|
+
this.#messageRequestsOut = messageSenderRequestsOut;
|
|
322
|
+
this.#messageResponsesIn = messageReceiverResponsesIn;
|
|
323
|
+
this.#configuredOutbound = true;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Used to add an additional {@link MessageObserver} to the connection for the incoming message requests.
|
|
328
|
+
*
|
|
329
|
+
* @method
|
|
330
|
+
* @param {MessageObserver} messageObserver
|
|
331
|
+
* @public
|
|
332
|
+
*/
|
|
333
|
+
addMessageObserverRequestsIn( messageObserver ) {
|
|
334
|
+
this.#messageRequestsIn.addMessageObserver( messageObserver );
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Used to add an additional {@link MessageObserver} to the connection for the incoming message responses.
|
|
339
|
+
*
|
|
340
|
+
* @method
|
|
341
|
+
* @param {MessageObserver} messageObserver
|
|
342
|
+
* @public
|
|
343
|
+
*/
|
|
344
|
+
addMessageObserverResponsesIn( messageObserver ) {
|
|
345
|
+
this.#messageResponsesIn.addMessageObserver( messageObserver );
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Used to mark the connection with the provided identifier as disrupted.
|
|
350
|
+
*
|
|
351
|
+
* @method
|
|
352
|
+
* @param {string} identifier The identifier of the observed connection.
|
|
353
|
+
* @override
|
|
354
|
+
* @public
|
|
355
|
+
*/
|
|
356
|
+
onConnectionDisrupted( identifier ) {
|
|
357
|
+
this.#disruptedConnections.push( identifier );
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Used to mark the connection with the provided identifier as recovered.
|
|
362
|
+
* <br/>
|
|
363
|
+
* NOTE: This will also result in enabling the message exchange if no connections are currently disrupted.
|
|
364
|
+
*
|
|
365
|
+
* @method
|
|
366
|
+
* @param {string} identifier The identifier of the observed connection.
|
|
367
|
+
* @override
|
|
368
|
+
* @public
|
|
369
|
+
*/
|
|
370
|
+
onConnectionRecovered( identifier ) {
|
|
371
|
+
_.pull( this.#disruptedConnections, identifier );
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Used to mark the connection with the provided identifier as disrupted.
|
|
376
|
+
*
|
|
377
|
+
* @method
|
|
378
|
+
* @param {string} identifier The identifier of the observed connection.
|
|
379
|
+
* @override
|
|
380
|
+
* @public
|
|
381
|
+
*/
|
|
382
|
+
onConnectionLost( identifier ) {
|
|
383
|
+
// TODO: implement triggering of a graceful shutdown of the service instance
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Used only for the message tracer.
|
|
388
|
+
*
|
|
389
|
+
* @method
|
|
390
|
+
* @param {string} identifier The identifier of the observed connection.
|
|
391
|
+
* @param {Message} message The message for processing.
|
|
392
|
+
* @returns {Message} The message that was received.
|
|
393
|
+
* @override
|
|
394
|
+
* @public
|
|
395
|
+
*/
|
|
396
|
+
onMessage( identifier, message ) {
|
|
397
|
+
message.destination.instanceID = this.#instanceID;
|
|
398
|
+
|
|
399
|
+
if ( MessageExchange.connectionNameRequestsIn === identifier ) {
|
|
400
|
+
messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_REQUEST, messageTracer.dispatchEvent.RECEIVED, messageTracer.messageState.PENDING );
|
|
401
|
+
} else if ( MessageExchange.connectionNameResponsesIn === identifier ) {
|
|
402
|
+
messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_RESPONSE, messageTracer.dispatchEvent.RECEIVED, messageTracer.messageState.PROCESSED );
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return message;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Used to check whether the connection with the provided identifier is currently in recovery mode.
|
|
410
|
+
*
|
|
411
|
+
* @method
|
|
412
|
+
* @param {string} identifier The identifier of the connection.
|
|
413
|
+
* @returns {boolean} Will return 'true' if the connection is currently disrupted and not yet recovered.
|
|
414
|
+
* @public
|
|
415
|
+
*/
|
|
416
|
+
isConnectionInRecovery( identifier ) {
|
|
417
|
+
return this.#disruptedConnections.indexOf( identifier ) !== -1;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Used to send a message request. Override of this method assumes that the message itself contains enough
|
|
422
|
+
* information to determine the sending destination.
|
|
423
|
+
*
|
|
424
|
+
* @method
|
|
425
|
+
* @param {Message} message The message request to send.
|
|
426
|
+
* @returns {Promise}
|
|
427
|
+
* @abstract
|
|
428
|
+
* @public
|
|
429
|
+
*/
|
|
430
|
+
sendMessageRequest( message ) {
|
|
431
|
+
return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.sendMessageRequest.name } ) );
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Used to send a message response. Override of this method assumes that the message itself contains enough
|
|
436
|
+
* information to determine the sending destination.
|
|
437
|
+
*
|
|
438
|
+
* @method
|
|
439
|
+
* @param {Message} message The message response to send.
|
|
440
|
+
* @returns {Promise}
|
|
441
|
+
* @abstract
|
|
442
|
+
* @public
|
|
443
|
+
*/
|
|
444
|
+
sendMessageResponse( message ) {
|
|
445
|
+
return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.sendMessageResponse.name } ) );
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
}
|
|
449
|
+
|
|
450
450
|
module.exports = MessageExchange;
|