@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 +41 -0
- package/README.md +47 -12
- package/bin/start-instance.js +45 -18
- package/components/auditing.js +8 -5
- package/components/connection-observer.js +6 -3
- package/components/exchange/default/default-message-exchange.js +8 -5
- package/components/exchange/default/default-message-receiver.js +13 -6
- package/components/exchange/default/default-message-sender.js +13 -6
- package/components/exchange/message-dispatcher.js +20 -13
- package/components/exchange/message-exchange.js +65 -26
- package/components/exchange/message-handler.js +7 -4
- package/components/exchange/message-memory-cache.js +23 -6
- package/components/exchange/message-observer.js +6 -3
- package/components/exchange/message-receiver.js +8 -5
- package/components/exchange/message-sender.js +7 -4
- package/components/exchange/message-tracer.js +143 -94
- package/components/service-caller.js +11 -8
- package/components/service-consumer.js +25 -6
- package/components/service-executor.js +44 -19
- package/components/service-instance.js +44 -26
- package/components/service-provider.js +26 -7
- package/integrations/gcloud-integration.js +8 -4
- package/integrations/redis-integration.js +140 -45
- package/package.json +7 -7
- package/utils/cache.js +29 -9
- package/utils/config.js +14 -3
- package/utils/exceptions.js +6 -3
- package/utils/localization.js +7 -4
- package/utils/logger.js +8 -6
- package/utils/tools.js +7 -4
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
|
|
16
|
-
* Flexibility
|
|
17
|
-
* Reliability
|
|
18
|
-
* Security
|
|
19
|
-
* Scalability
|
|
20
|
-
* Containerization
|
|
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
|
|
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
|
|
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
|
|
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`
|
package/bin/start-instance.js
CHANGED
|
@@ -1,25 +1,42 @@
|
|
|
1
1
|
/*
|
|
2
|
-
*
|
|
3
|
-
*
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
65
|
-
|
|
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
|
-
//
|
|
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
|
+
}
|
package/components/auditing.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/*
|
|
2
|
-
*
|
|
3
|
-
*
|
|
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
|
|
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
|
-
*
|
|
3
|
-
*
|
|
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
|
-
*
|
|
3
|
-
*
|
|
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
|
|
37
|
-
* @param {boolean} configureOutbound If set to 'true' it tells the message exchange to
|
|
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
|
-
*
|
|
3
|
-
*
|
|
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
|
|
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
|
|
60
|
-
|
|
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
|
-
*
|
|
3
|
-
*
|
|
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
|
|
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
|
|
85
|
-
|
|
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
|
-
*
|
|
3
|
-
*
|
|
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
|
|
44
|
-
* @param {boolean} configureOutbound If set to 'true' it tells the message exchange to
|
|
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
|
-
|
|
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 );
|