@ti-engine/core 1.1.4 → 1.1.8

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 CHANGED
@@ -1,5 +1,46 @@
1
1
  # ti-engine changelog
2
2
 
3
+ This document will contain the list of changes made to the framework. The format is based on the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification.
4
+
5
+ ## Version 1.1.8
6
+ * feat(auditing): change export of the singleton class in an `instance` variable for consistency and clarity
7
+ * feat(message dispatcher): change export of the singleton class in an `instance` variable for consistency and clarity
8
+ * feat(cache): change export of the singleton class in an `instance` variable for consistency and clarity
9
+ * feat(service executor): implement service registration retry policy
10
+
11
+ ## Version 1.1.7
12
+ * feat(start instance): add support for the detection of `SIGBREAK` events and graceful shutdown on Windows
13
+ * feat(service instance)!: prevent the initialization of multiple `ServiceInstance` within the same process
14
+ * feat(message tracer)!: covert to singleton instance and add initialization method
15
+ * feat(message dispatcher): initialize the message tracer on start before message exchange is enabled
16
+ * fix(message tracer): optimize `recordTraceEntry` to not call set JSON command on every request
17
+ * fix(gcloud integration): fix the bool conversion of the `TI_GCLOUD_ENABLED` ENV variable
18
+ * fix(redis integration): update links to official commands documentation
19
+
20
+ ## Version 1.1.6
21
+ * feat(start instance): add fail-fast mode as default behavior on promise unhandled rejections
22
+ * feat(start instance): implement functionality to derive safe default service domain name when none is provided in the configuration
23
+ * feat(config): add support for new ENV variable `TI_FAIL_FAST_ON_UNHANDLED_OFF` that controls the fail-fast mode
24
+ * feat(service instance): ensure instance ID naming standard is followed when creating new instances and no ID is provided in the configuration
25
+ * feat(redis integration): marked command `hmset` as deprecated (according to official documentation)
26
+ * feat(redis integration)!: change redis client default behavior: set to automatically resend all pending commands on connection recovery with no limit on the retry attempts. This behavior cannot be changed. Arguments `autoRetryUnfulfilled` and `maxRetries` have been removed from the constructor
27
+ * feat(redis integration)!: add options to configure redis connection retry policy. This can be controlled with two new arguments in the constructor `retryMaxIntervalMs` and `retryMaxAttempts`.
28
+ * feat(redis integration)!: improve and extend the behavior of pub/sub implementation functionality. The `subscribeCommand` method can now only subscribe once to the same channel. The client instance will keep a map of all channels it has subscribed to. To unsubscribe, use the `unsubscribeCommand` method
29
+ * feat(redis integration): add a `shutDown` method to gracefully close a redis connection. This is now used on instance shut down sequence as well as in the default message sender and receiver implementations
30
+ * fix(start instance): fix the logging of reason for unhandled rejections and multiple resolves
31
+ * fix(service instance): use the static service domain name to initialize the health check instead of the ENV variable
32
+ * fix(redis integration): add detection of ReJSON2 in the verification of JSON support in the redis server
33
+ * build(npm): update npm dependencies to their latest versions
34
+ * docs: add section about ENV variables to the `README.md` file
35
+
36
+ ## Version 1.1.5
37
+
38
+ * fix(service instance): add overrides of the `reportHealthy` method in `ServiceConsumer` and `ServiceProvider` classes
39
+ * fix(tester): implement `reportHealthy` method
40
+ * docs(license): add a `LICENSE` file
41
+ * docs(license): change all licensing information in source files to GNU 3.0
42
+ * docs: improve the information in `README.md` file
43
+
3
44
  ## Version 1.1.4
4
45
 
5
46
  * feat(service instance): expose method `reportHealthy` and mark it as virtual to allow for overrides with custom health status reporting logic
package/README.md CHANGED
@@ -12,12 +12,12 @@ The framework is created based on a decade of professional experience with the u
12
12
 
13
13
  This is what you gain by using **ti-engine** in your project:
14
14
 
15
- * Simplicity - begin productive work within minutes and get to codding you business logic
16
- * Flexibility - go as complex as you need to in your implementation
17
- * Reliability - message exchange between the services is constantly tracked across the entire ecosystem
18
- * Security - messages are encrypted in transit and cannot be modified by external agents
19
- * Scalability - serve mullions of requests by multiplying stateless service instances (hardware limitations still apply)
20
- * Containerization - go with containers from the very start as the framework is designed to work in such an environment
15
+ * Simplicity: begin productive work within minutes and get to codding you business logic
16
+ * Flexibility: go as complex as you need to in your implementation
17
+ * Reliability: message exchange between the services is constantly tracked across the entire ecosystem
18
+ * Security: messages are encrypted in transit and cannot be modified by external agents
19
+ * Scalability: serve mullions of requests by multiplying stateless service instances (hardware limitations still apply)
20
+ * Containerization: go with containers from the very start as the framework is designed to work in such an environment
21
21
 
22
22
  These are just some benefits **ti-engine** offers. Get to know it better to find out more ways in which it can help you improve productivity.
23
23
 
@@ -25,12 +25,12 @@ These are just some benefits **ti-engine** offers. Get to know it better to find
25
25
 
26
26
  Being a messaging system, the **ti-engine** relies on a message broker for the actual exchange of messages between microservice instances. The default implementation of the framework uses [Redis](https://redis.io/) cache, however, you could create your own implementation using something like [Rabbit MQ](https://www.rabbitmq.com/). See the [Advanced topics](#advanced-topics) section of this documentation for guides on how to do this. For now let's focus on the default setup.
27
27
 
28
- In order to run the basic ti-engine framework you will need a couple of things:
28
+ In order to run the basic ti-engine framework, you will need a couple of things:
29
29
 
30
30
  * A local [node.js installation](https://nodejs.org/en/download/) with a minimum version of **14.17.0**
31
31
  * A local or remote [Redis cache installation](https://redis.io/download) with a minimum version of **5.0.14**
32
32
 
33
- If you are working under Windows 10+ OS and you need to install Redis, take a look at this [guide](https://redis.com/blog/redis-on-windows-10/). You could also use [Redis Cloud](https://app.redislabs.com/) for development purposes as it offers free basic account. You can configure your connection to remote Redis server using the following ENV variables:
33
+ If you are working under Windows 10+ OS and you need to install Redis, take a look at this [guide](https://redis.com/blog/redis-on-windows-10/). You could also use [Redis Cloud](https://app.redislabs.com/) for development purposes as it offers free basic account. You can configure your connection to a remote Redis server using the following ENV variables:
34
34
 
35
35
  * `TI_MEMORY_CACHE_AUTH_KEY` can be used to provide the Redis password if there is any at all.
36
36
  * `TI_MEMORY_CACHE_REDIS_DB` can be used to specify the Redis DB you want to use. Make sure to set the correct number as for example Redis Cloud only uses DB `0`.
@@ -75,7 +75,7 @@ Now let's analyse that output. For the sake of completeness, the `[timestamp]` a
75
75
  At the start of the output log you can see a NOTICE that tells you a couple of important things:
76
76
 
77
77
  * The instance name - in this case `tester-service`. In the terminology of the framework, this is also known as a _service domain name_.
78
- * The _instance identificator_. It is an uuid string with a `ti-` prefix, that is generated by the framework at process start. It can and will be used to trace the messages during their movement through the microservice ecosystem. But more on that later.
78
+ * The _instance identifier_. It is an uuid string with a `ti-` prefix, that is generated by the framework at process start. It can and will be used to trace the messages during their movement through the microservice ecosystem. But more on that later.
79
79
 
80
80
  Following that come a couple of INFO lines that inform you about the microservice interface state. The framework starts with the process of registration of _business services_ within the service domain of the microservice `tester-service` and successfully adds 2 such services. The necessary information for this is read from a JSON config file included in the package. We'll get into more details on what this all means in the section [Creating a microservice](#creating-a-microservice).
81
81
 
@@ -158,7 +158,7 @@ This tier comprises the actual implementation of your application. Its structure
158
158
  * It needs to take care of any type of stateful behavior like user sessions or transactions
159
159
  * It needs to act as the primary interface between users and your application thus handling access management and user interactions
160
160
 
161
- Depending on the type of software you are building, tier 3 can be an API Gateway, a Web application, backend for a Mobile application, or anything like that.
161
+ Depending on the type of software you are building, tier 3 can be an API Gateway, a Web application, backend for a Mobile application or anything like that.
162
162
 
163
163
  ## Creating a microservice
164
164
 
@@ -226,9 +226,10 @@ You can find the full list of available ENV variables and what they do below in
226
226
 
227
227
  #### Application specific files
228
228
 
229
- Now let's look inside the `bin` folder. The two files there are the ones specified in the `.env` file. The `tester-service.js` contains the implementation of the `ServiceProvider` class. It has just three methods that contain its behavior:
229
+ Now let's look inside the `bin` folder. The two files there are the ones specified in the `.env` file. The `tester-service.js` contains the implementation of the `ServiceProvider` class. It has just a few methods that contain its behavior:
230
230
 
231
231
  * Method `onStart` overrides the base one from the parent class and is invoked automatically by the framework once initialization of the microservice is complete. In this case the method invokes the execution of the test sequence just once and then the microservice remains dormant but active.
232
+ * Method `reportHealthy` overrides but essentially just calls the same base method. Its only purpose here is to draw your attention to its existence and the possibility to implement your own health status reporting functionality if you want.
232
233
  * Method `verifyAccess` also overrides the base method and shows a very basic example of how to implement user access verification on business service level. Each time a service in the `ti-tester-service` is called, the framework will trigger this method and will only allow processing if there is a non-undefined value inside the `authToken` variable.
233
234
  * Method `#executeTests` is a custom private method that contains the test sequence itself. It is called by the `onStart` method just once per microservice start. Inside you can see two examples of calling a business service—in both cases the tester microservice is calling itself. In more practical situation, however, these calls would be directed towards other service domains.
234
235
 
@@ -337,6 +338,30 @@ And with this step we are done. The new microservice is now operational. You can
337
338
 
338
339
  ## Using the framework
339
340
 
341
+ ### Environment variables
342
+
343
+ These are the system-level ENV variables that can be used to configure the framework. Use a .env file or corresponding containerization features to set the variables you need. Not all of these are mandatory or even required for every microservice you create. Consult the documentation for more details.
344
+
345
+ TI_AUDITING_LOG_MIN_LEVEL
346
+ : Type: Optional
347
+ : Specifies the minimum log level that should be sent to the log output stream. The framework will filter out all log entries with level below this value. The default value is `200` (corresponding to INFO).
348
+
349
+ TI_FAIL_FAST_ON_UNHANDLED_OFF
350
+ : Type: Optional
351
+ : Specifies whether the framework fail-fast on unhandled promise behavior should be turned off. Set this to `true` to disable the default behavior. The default value is `false`.
352
+
353
+ TI_INSTANCE_CLASS
354
+ : Type: Required
355
+ : Specifies the relative path to the implementation of the `ServiceInstance` framework class—in this case a `ServiceProvider`. As stated above, the path is relative to the working directory of the `node` process. This variable is mandatory for every microservice you create with the **ti-engine**. If it is not provided the microservice won't be able to start at all, and you will get an exception.
356
+
357
+ TI_INSTANCE_CONFIG
358
+ : Type: Optional
359
+ : Specifies the relative path to the configuration data for the microservice. Technically, you can omit this variable and the microservice will still start successfully with an empty configuration. There are very few cases, however, where this would be applicable.
360
+
361
+ TI_INSTANCE_NAME
362
+ : Type: Required
363
+ : Specifies the _service domain_ name provided for the microservice. It has to be _unique_ in the context of the microservice ecosystem. If not provided, the framework will attempt to extract this information from the name of the implementation file. That is not a recommended approach though as it might cause hard to identify errors later.
364
+
340
365
  ### Framework settings
341
366
 
342
367
  Here you can find all settings used by **ti-engine** together with information on what they do. They are defined inside the `config` module and the full list can be accessed through the public `setting` enum. To get the current value of a setting, you can use the public method `getSetting` from the same module. Some settings can be overridden by providing ENV variables as specified below at node application start up.
@@ -397,7 +422,17 @@ MEMORY_CACHE_REDIS_HOST
397
422
  MEMORY_CACHE_REDIS_PORT
398
423
  : JSON path `memoryCache.redisPort`, type `number`, default `6379`
399
424
  : ENV variable `TI_MEMORY_CACHE_REDIS_PORT`
400
- : This setting holds the Redis server port.
425
+ : This setting holds the Redis server port. By default, Redis uses `6379` however many implementations might use a custom port that needs to be specified in the connection settings.
426
+
427
+ MEMORY_CACHE_RETRY_MAX_ATTEMPTS
428
+ : JSON path `memoryCache.retryMaxAttempts`, type `number`, default `undefined`
429
+ : ENV variable `TI_MEMORY_CACHE_RETRY_MAX_ATTEMPTS`
430
+ : This setting holds the maximum number of attempts to (re)connect to the Redis server. By default there is no limit.
431
+
432
+ MEMORY_CACHE_RETRY_MAX_INTERVAL
433
+ : JSON path `memoryCache.retryMaxInterval`, type `number`, default `1000`
434
+ : ENV variable `TI_MEMORY_CACHE_RETRY_MAX_INTERVAL`
435
+ : This setting holds the maximum interval in milliseconds between retries when the Redis server is not available.
401
436
 
402
437
  MEMORY_CACHE_USER
403
438
  : JSON path `memoryCache.user`, type `string`, default `default`
@@ -1,25 +1,42 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
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-2025 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
+ */
5
8
 
6
9
  "use strict";
7
10
 
8
- const _ = require( "lodash" );
9
11
  const path = require( "path" );
10
12
 
11
- // load any ENV variables defined in a .env file - before including any framework files:
13
+ // Load any ENV variables defined in a .env file - before including any framework files:
12
14
  require( "dotenv" ).config( { path: path.join( process.cwd(), ".env" ) } );
13
15
 
14
16
  const tools = require( "#tools" );
15
17
  const logger = require( "#logger" );
16
18
 
17
- // configure the current instance variables before requiring any platform modules and store the necessary ones in memory cache:
19
+ // Configure the current instance variables before requiring any platform modules and store the necessary ones in memory cache:
18
20
  process.env.TI_INSTANCE_ID = "ti-" + tools.getUUID();
19
21
  process.env.TI_INSTANCE_CLASS = process.env.TI_INSTANCE_CLASS || "";
20
- process.env.TI_INSTANCE_NAME = process.env.TI_INSTANCE_NAME || _.last( _.split( process.env.TI_INSTANCE_CLASS, "/" ) );
21
22
 
22
- // configure the process error handlers:
23
+ // Derive a safe default service domain name if not explicitly provided:
24
+ // - Normalize path separators
25
+ // - Strip directory and file extension
26
+ const defaultNameFromClass = ( () => {
27
+ try {
28
+ const normalized = ( process.env.TI_INSTANCE_CLASS || "" ).replace( /\\/g, "/" );
29
+ const base = path.posix.basename( normalized );
30
+ const name = path.parse( base ).name;
31
+ return name || "";
32
+ } catch {
33
+ return "";
34
+ }
35
+ } )();
36
+
37
+ process.env.TI_INSTANCE_NAME = process.env.TI_INSTANCE_NAME || defaultNameFromClass;
38
+
39
+ // Configure the process error handlers:
23
40
 
24
41
  /**
25
42
  * Will be used to gracefully shut down the instance.
@@ -34,35 +51,45 @@ process.env.TI_INSTANCE_NAME = process.env.TI_INSTANCE_NAME || _.last( _.split(
34
51
  let shutDownInstance = ( exitCode ) => {
35
52
  };
36
53
 
37
- // this event will handle the process termination (Ctrl + C):
54
+ // This event will handle the process termination (Ctrl + C):
38
55
  process.on( "SIGINT", () => {
39
56
  logger.log( `SIGINT event detected in main instance process.`, logger.logSeverity.NOTICE );
40
57
  shutDownInstance( 0 );
41
58
  } );
42
59
 
43
- // this event will handle the process termination (CMD close):
60
+ // This event will handle the process termination via terminal hangup (CMD close) - not delivered on all platforms:
44
61
  process.on( "SIGHUP", () => {
45
62
  logger.log( `SIGHUP event detected in main instance process.`, logger.logSeverity.NOTICE );
46
63
  shutDownInstance( 0 );
47
64
  } );
48
65
 
49
- // this event will handle the process termination:
66
+ // This event will handle the process termination:
50
67
  process.on( "SIGTERM", () => {
51
68
  logger.log( `SIGTERM event detected in main instance process.`, logger.logSeverity.NOTICE );
52
69
  shutDownInstance( 0 );
53
70
  } );
54
71
 
55
- process.on( "unhandledRejection", ( reason, promise ) => {
72
+ // Handle Windows console break (Ctrl + Break):
73
+ process.on( "SIGBREAK", () => {
74
+ logger.log( `SIGBREAK event detected in main instance process.`, logger.logSeverity.NOTICE );
75
+ shutDownInstance( 0 );
76
+ } );
77
+
78
+ process.on( "unhandledRejection", ( reason ) => {
79
+ // Check if the fail-fast behavior has been forcefully disabled:
80
+ const failFastDisabled = tools.toBool( process.env.TI_FAIL_FAST_ON_UNHANDLED_OFF || "" );
56
81
  logger.log( `Unhandled promise rejection identified! Make sure this isn't a software bug.`, logger.logSeverity.WARNING, {
57
- reason: reason,
58
- promise: tools.stringifyJSON( promise )
82
+ reason: tools.errorToJSON && reason instanceof Error ? tools.errorToJSON( reason ) : reason
59
83
  } );
84
+ if ( failFastDisabled !== true ) {
85
+ setImmediate( () => process.exit( 1 ) );
86
+ }
60
87
  } );
61
88
 
62
89
  process.on( "multipleResolves", ( type, promise, reason ) => {
63
90
  logger.log( `Multiple promise resolves detected! Make sure this isn't a software bug.`, logger.logSeverity.WARNING, {
64
- reason: reason,
65
- promise: tools.stringifyJSON( promise )
91
+ type,
92
+ reason: tools.errorToJSON && reason instanceof Error ? tools.errorToJSON( reason ) : reason
66
93
  } );
67
94
  } );
68
95
 
@@ -71,7 +98,7 @@ process.on( "uncaughtException", ( error ) => {
71
98
  setImmediate( () => process.exit( 1 ) );
72
99
  } );
73
100
 
74
- // start the instance:
101
+ // Start the instance:
75
102
  try {
76
103
  logger.log( `Starting new instance of type '${ process.env.TI_INSTANCE_NAME }' with instance ID '${ process.env.TI_INSTANCE_ID }'.`, logger.logSeverity.NOTICE );
77
104
 
@@ -107,4 +134,4 @@ try {
107
134
  } catch ( error ) {
108
135
  logger.log( `Error detected in the instance startup script!`, logger.logSeverity.ALERT, error );
109
136
  setImmediate( () => process.exit( 1 ) );
110
- }
137
+ }
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
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-2025 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
+ */
5
8
 
6
9
  const _ = require( "lodash" );
7
10
  const tools = require( "#tools" );
@@ -17,7 +20,7 @@ const gcloud = require( "#gcloud-integration" );
17
20
  * @property {string} reporter
18
21
  * @property {string} message The actual log message.
19
22
  * @property {number} timestamp The timestamp of the log entry in UTC time.
20
- * @property {Object} data Additional JSON data to accompany the message.
23
+ * @property {Object} data Additional JSON data to go with the message.
21
24
  */
22
25
 
23
26
  /**
@@ -160,4 +163,4 @@ class Auditing {
160
163
  }
161
164
 
162
165
  const instance = new Auditing();
163
- module.exports = Object.freeze( instance );
166
+ module.exports.instance = Object.freeze( instance );
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
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-2023 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
+ */
5
8
 
6
9
  const exceptions = require( "#exceptions" );
7
10
 
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
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-2023 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
+ */
5
8
 
6
9
  const MessageExchange = require( "#message-exchange" );
7
10
  const config = require( "#config" );
@@ -33,8 +36,8 @@ class DefaultMessageExchange extends MessageExchange {
33
36
  * NOTE: This will create and prepare all necessary message handlers and then enable them simultaneously.
34
37
  *
35
38
  * @method
36
- * @param {boolean} configureInbound If set to 'true' it tells the message exchange to setup inbound messaging.
37
- * @param {boolean} configureOutbound If set to 'true' it tells the message exchange to setup outbound messaging.
39
+ * @param {boolean} configureInbound If set to 'true' it tells the message exchange to set up inbound messaging.
40
+ * @param {boolean} configureOutbound If set to 'true' it tells the message exchange to set up outbound messaging.
38
41
  * @returns {Promise}
39
42
  * @override
40
43
  * @public
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
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-2023 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
+ */
5
8
 
6
9
  const MessageReceiver = require( "#message-receiver" );
7
10
  const memoryCache = require( "#message-memory-cache" );
@@ -46,7 +49,7 @@ class DefaultMessageReceiver extends MessageReceiver {
46
49
  }
47
50
 
48
51
  /**
49
- * Used to shutdown and disable the communication behavior of the handler.
52
+ * Used to shut down and disable the communication behavior of the handler.
50
53
  *
51
54
  * @method
52
55
  * @returns {Promise}
@@ -56,8 +59,12 @@ class DefaultMessageReceiver extends MessageReceiver {
56
59
  disable() {
57
60
  return new Promise( ( resolve, reject ) => {
58
61
  this.isAvailable = false;
59
- this.#memoryCache = null;
60
- resolve();
62
+ this.#memoryCache.shutDown().then( () => {
63
+ this.#memoryCache = null;
64
+ resolve();
65
+ } ).catch( ( error ) => {
66
+ reject( exceptions.raise( error ) );
67
+ } );
61
68
  } );
62
69
  }
63
70
 
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
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-2023 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
+ */
5
8
 
6
9
  const MessageSender = require( "#message-sender" );
7
10
  const _ = require( "lodash" );
@@ -71,7 +74,7 @@ class DefaultMessageSender extends MessageSender {
71
74
  }
72
75
 
73
76
  /**
74
- * Used to shutdown and disable the communication behavior of the handler.
77
+ * Used to shut down and disable the communication behavior of the handler.
75
78
  *
76
79
  * @method
77
80
  * @returns {Promise}
@@ -81,8 +84,12 @@ class DefaultMessageSender extends MessageSender {
81
84
  disable() {
82
85
  return new Promise( ( resolve, reject ) => {
83
86
  this.isAvailable = false;
84
- this.#memoryCache = null;
85
- resolve();
87
+ this.#memoryCache.shutDown().then( () => {
88
+ this.#memoryCache = null;
89
+ resolve();
90
+ } ).catch( ( error ) => {
91
+ reject( exceptions.raise( error ) );
92
+ } );
86
93
  } );
87
94
  }
88
95
  }
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
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-2025 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
+ */
5
8
 
6
9
  const tools = require( "#tools" );
7
10
  const exceptions = require( "#exceptions" );
@@ -40,15 +43,19 @@ class MessageDispatcher {
40
43
  *
41
44
  * @method
42
45
  * @param {MessageExchange} messageExchange The message exchange instance to be used by the dispatcher.
43
- * @param {boolean} configureInbound If set to 'true' it tells the message exchange to setup inbound messaging.
44
- * @param {boolean} configureOutbound If set to 'true' it tells the message exchange to setup outbound messaging.
46
+ * @param {boolean} configureInbound If set to 'true' it tells the message exchange to set up inbound messaging.
47
+ * @param {boolean} configureOutbound If set to 'true' it tells the message exchange to set up outbound messaging.
45
48
  * @returns {Promise}
46
49
  * @public
47
50
  */
48
51
  initialize( messageExchange, configureInbound, configureOutbound ) {
49
52
  return new Promise( ( resolve, reject ) => {
50
53
  this.#messageExchange = messageExchange;
51
- this.#messageExchange.enableMessaging( configureInbound, configureOutbound ).then( () => {
54
+
55
+ // Initialize the message tracer before enabling the message exchange:
56
+ messageTracer.instance.initialize().then( () => {
57
+ this.#messageExchange.enableMessaging( configureInbound, configureOutbound );
58
+ } ).then( () => {
52
59
  resolve();
53
60
  } ).catch( ( error ) => {
54
61
  reject( exceptions.raise( error ) );
@@ -92,13 +99,13 @@ class MessageDispatcher {
92
99
  logger.log( `Retrying to send message response with chain ID: ${ message.chainID }. This is attempt ${ attempt }...`, logger.logSeverity.NOTICE );
93
100
  } );
94
101
 
95
- messageTracer.recordTraceEntry( message, messageTracer.messageType.MESSAGE_REQUEST, messageTracer.dispatchEvent.SENT, messageTracer.messageState.PENDING );
102
+ messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_REQUEST, messageTracer.dispatchEvent.SENT, messageTracer.messageState.PENDING );
96
103
 
97
104
  retry.execute( this.#messageExchange, this.#messageExchange.sendMessageRequest, [ message ] ).then( () => {
98
- messageTracer.recordTraceEntry( message, messageTracer.messageType.MESSAGE_REQUEST, messageTracer.dispatchEvent.DELIVERED, messageTracer.messageState.PENDING );
105
+ messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_REQUEST, messageTracer.dispatchEvent.DELIVERED, messageTracer.messageState.PENDING );
99
106
  resolve( message.messageID );
100
107
  } ).catch( ( error ) => {
101
- messageTracer.recordTraceEntry( message, messageTracer.messageType.MESSAGE_REQUEST, messageTracer.dispatchEvent.FAILED, messageTracer.messageState.PENDING );
108
+ messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_REQUEST, messageTracer.dispatchEvent.FAILED, messageTracer.messageState.PENDING );
102
109
  reject( exceptions.raise( error ) );
103
110
  } );
104
111
  } );
@@ -122,13 +129,13 @@ class MessageDispatcher {
122
129
  logger.log( `Retrying to send message response with chain ID: ${ message.chainID }. This is attempt ${ attempt }...`, logger.logSeverity.NOTICE );
123
130
  } );
124
131
 
125
- messageTracer.recordTraceEntry( message, messageTracer.messageType.MESSAGE_RESPONSE, messageTracer.dispatchEvent.SENT, messageTracer.messageState.PROCESSED );
132
+ messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_RESPONSE, messageTracer.dispatchEvent.SENT, messageTracer.messageState.PROCESSED );
126
133
 
127
134
  retry.execute( this.#messageExchange, this.#messageExchange.sendMessageResponse, [ message ] ).then( () => {
128
- messageTracer.recordTraceEntry( message, messageTracer.messageType.MESSAGE_RESPONSE, messageTracer.dispatchEvent.DELIVERED, messageTracer.messageState.PROCESSED );
135
+ messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_RESPONSE, messageTracer.dispatchEvent.DELIVERED, messageTracer.messageState.PROCESSED );
129
136
  resolve();
130
137
  } ).catch( ( error ) => {
131
- messageTracer.recordTraceEntry( message, messageTracer.messageType.MESSAGE_RESPONSE, messageTracer.dispatchEvent.FAILED, messageTracer.messageState.PROCESSED );
138
+ messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_RESPONSE, messageTracer.dispatchEvent.FAILED, messageTracer.messageState.PROCESSED );
132
139
  reject( exceptions.raise( error ) );
133
140
  } );
134
141
  } );
@@ -159,4 +166,4 @@ class MessageDispatcher {
159
166
  }
160
167
 
161
168
  const instance = new MessageDispatcher();
162
- module.exports = Object.freeze( instance );
169
+ module.exports.instance = Object.freeze( instance );