@ti-engine/core 1.3.3 → 1.3.5
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 +8 -0
- package/README.md +94 -89
- package/components/service-caller.js +1 -1
- package/components/service-consumer.js +2 -2
- package/components/service-instance.js +3 -3
- package/components/service-provider.js +2 -2
- package/integrations/redis-integration.js +11 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
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
4
|
|
|
5
|
+
## Version 1.3.5
|
|
6
|
+
* fix(redis integration): fix a duplicated log entry on connection ready event if multiple observers are registered
|
|
7
|
+
* feat(service caller)!: change log level of error result in `process` method from `ERROR` to `DEBUG`. Implementers are expected to handle this and decide if the error should be propagated further or not
|
|
8
|
+
* docs: update and fix various issues with the `README.md` file
|
|
9
|
+
|
|
10
|
+
## Version 1.3.4
|
|
11
|
+
* fix(service instance): fix the way `ServiceConfiguration` is propagated via child classes and remove unnecessary defaults. Also update the relevant JSDoc
|
|
12
|
+
|
|
5
13
|
## Version 1.3.3
|
|
6
14
|
* feat(exceptions): add new parameter `includeData` to `Exception.asJSON` method which allows the exclusion of the data parameter from the returned JSON
|
|
7
15
|
* feat(exceptions): remove several excessive exception codes that were unlikely to be used
|
package/README.md
CHANGED
|
@@ -8,32 +8,32 @@ The **ti-engine** is an open source, free to use—both for personal and commerc
|
|
|
8
8
|
|
|
9
9
|
## Why ti-engine?
|
|
10
10
|
|
|
11
|
-
The framework is created based on a decade of professional experience with the utilized technologies and architectural approach.
|
|
11
|
+
The framework is created based on a decade of professional experience with the utilized technologies and architectural approach. Its primary goal is to provide you with a lightweight and flexible solution that can help you quickly build a microservice ecosystem with any degree of size and complexity.
|
|
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 your 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
|
|
|
24
24
|
## Prerequisites & installation
|
|
25
25
|
|
|
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
|
|
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
|
-
|
|
28
|
+
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
|
|
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 as it offers a 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
|
-
* `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`.
|
|
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`.
|
|
37
37
|
* `TI_MEMORY_CACHE_REDIS_HOST` can be used to provide the remote host. This can be an IP or URL depending on your setup.
|
|
38
38
|
* `TI_MEMORY_CACHE_REDIS_PORT` can be used to provide the remote port. By default, Redis uses `6379` however many implementations might use a custom port that needs to be specified in the connection settings.
|
|
39
39
|
|
|
@@ -41,10 +41,10 @@ To get the framework itself, use the command `npm install @ti-engine/core`. And
|
|
|
41
41
|
|
|
42
42
|
## Getting started
|
|
43
43
|
|
|
44
|
-
To start using the **ti-engine**, you will have to make sure that all prerequisites are available and operational. However, before we get to the fun part you need to also consider a couple of
|
|
44
|
+
To start using the **ti-engine**, you will have to make sure that all prerequisites are available and operational. However, before we get to the fun part, you need to also consider a couple of crucial things while working with this framework:
|
|
45
45
|
|
|
46
46
|
1. The runtime configuration of the framework can be customized using ENV variables. These can be provided to node.js in all the standard ways, but there is also an option to include an `.env` file.
|
|
47
|
-
2. It loads your framework-related custom scripts and files dynamically, but it always assumes their provided paths are relative to the _current working directory_ (i.e
|
|
47
|
+
2. It loads your framework-related custom scripts and files dynamically, but it always assumes their provided paths are relative to the _current working directory_ (i.e., it uses `process.cwd()` to resolve the file paths). Be mindful of that whenever you declare file paths in the various settings.
|
|
48
48
|
|
|
49
49
|
Once you have everything else ready, you should download the **ti-engine** tester module with the command `npm install @ti-engine/tester`. The tester module packages an example microservice that shows the basic approach for using the framework. To make sure everything is working properly, you should try and start the tester service:
|
|
50
50
|
|
|
@@ -54,54 +54,59 @@ Once you have everything else ready, you should download the **ti-engine** teste
|
|
|
54
54
|
3. If everything was done properly, you should see the following output:
|
|
55
55
|
|
|
56
56
|
```text
|
|
57
|
-
[timestamp]: [instance-id] - notice - Starting new instance of type 'tester-service' with instance ID '[instance-id]'.
|
|
57
|
+
[timestamp]: [instance-id] - notice - Starting new instance of type 'ti-tester-service' with instance ID '[instance-id]'.
|
|
58
|
+
[timestamp]: [instance-id] - info - Connection to Redis server '127.0.0.1:6379' established by client 'system-cache' and is ready to be used.
|
|
59
|
+
[timestamp]: [instance-id] - info - Connection to Redis server '127.0.0.1:6379' established by client 'connection-msg-responses-out' and is ready to be used.
|
|
60
|
+
[timestamp]: [instance-id] - info - Connection to Redis server '127.0.0.1:6379' established by client 'connection-msg-requests-in' and is ready to be used.
|
|
61
|
+
[timestamp]: [instance-id] - info - Connection to Redis server '127.0.0.1:6379' established by client 'connection-msg-requests-out' and is ready to be used.
|
|
62
|
+
[timestamp]: [instance-id] - info - Connection to Redis server '127.0.0.1:6379' established by client 'connection-msg-responses-in' and is ready to be used.
|
|
58
63
|
[timestamp]: [instance-id] - info - Starting service registration process. There is NO default service handler provided.
|
|
59
64
|
[timestamp]: [instance-id] - info - Registration of defined services completed with 2 successful out of 2 total.
|
|
60
65
|
[timestamp]: [instance-id] - notice - Instance '[instance-id]' started successfully.
|
|
61
|
-
» {"nodeVersion":[node-version]}
|
|
62
|
-
[timestamp]: [instance-id] - info -
|
|
63
|
-
[timestamp]: [instance-id] - info - Connection to Redis server 127.0.0.1:6379 (re)established by client 'system-cache' and is ready to be used.
|
|
64
|
-
[timestamp]: [instance-id] - info - Connection to Redis server 127.0.0.1:6379 (re)established by client 'connection-msg-requests-in' and is ready to be used.
|
|
65
|
-
[timestamp]: [instance-id] - info - Connection to Redis server 127.0.0.1:6379 (re)established by client 'connection-msg-requests-out' and is ready to be used.
|
|
66
|
-
[timestamp]: [instance-id] - info - Connection to Redis server 127.0.0.1:6379 (re)established by client 'connection-msg-responses-in' and is ready to be used.
|
|
67
|
-
[timestamp]: [instance-id] - notice - Execution of service1 result:
|
|
66
|
+
» {"nodeVersion":[node-version],"operationMode":[mode]}
|
|
67
|
+
[timestamp]: [instance-id] - info - Execution of 'Test 1: Service call to a simple service without chained services' successful.
|
|
68
68
|
» {"isSuccessful":true,"payload":{"s1Timestamp":[timestamp]}}
|
|
69
|
-
[timestamp]: [instance-id] -
|
|
69
|
+
[timestamp]: [instance-id] - info - Execution of 'Test 2: Service call to a simple service with one chained service' successful.
|
|
70
70
|
» {"isSuccessful":true,"payload":{"s1Timestamp":[timestamp],"s2TimestampStart":[timestamp],"s2TimestampEnd":[timestamp]}}
|
|
71
|
+
[timestamp]: [instance-id] - info - Execution of 'Test 3: Service call to a non-existent service' successful.
|
|
72
|
+
» {"isSuccessful":false,"exception":{"exceptionID":[exception-id],"description":"The specified service is not found in the service registry."}}
|
|
73
|
+
[timestamp]: [instance-id] - notice - All service tests completed. Passed 3 out of 3.
|
|
71
74
|
```
|
|
72
75
|
|
|
73
|
-
Now let's
|
|
76
|
+
Now let's analyze that output. For the sake of completeness, the `[timestamp]` and `[instance-id]` are placeholders of the actual values you'll see there. The timestamps are in UTC and show a date followed by time.
|
|
74
77
|
|
|
75
|
-
At the start of the output log you can see a NOTICE that tells you a couple of important things:
|
|
78
|
+
At the start of the output log, you can see a `NOTICE` that tells you a couple of important things:
|
|
76
79
|
|
|
77
|
-
* The instance name - in this case `tester-service`. In the terminology of the framework, this is also known as a _service domain name_.
|
|
80
|
+
* The instance name - in this case `ti-tester-service`. In the terminology of the framework, this is also known as a _service domain name_.
|
|
78
81
|
* 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
82
|
|
|
80
|
-
|
|
83
|
+
The following five `INFO` lines inform you about the successful connections to Redis. The default configuration assumes that your Redis is running on localhost and uses the default port. If you have a different setup, you can provide the host and port via ENV variables. We'll cover that in the section [Using the framework](#using-the-framework).
|
|
84
|
+
|
|
85
|
+
Following that come a couple of `INFO` lines that inform you about the microservice interface state. The framework starts with the process of _business services_ registration within the service domain of the microservice `ti-tester-service` and successfully adds two 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
86
|
|
|
82
|
-
Once the initialization sequence has completed the framework informs you that the microservice instance has started successfully
|
|
87
|
+
Once the initialization sequence has completed, the framework informs you that the microservice instance has started successfully with a `NOTICE` entry.
|
|
88
|
+
|
|
89
|
+
If the framework encountered an error during initialization instead, you would see something like this instead:
|
|
83
90
|
|
|
84
91
|
```text
|
|
85
|
-
[timestamp]: [instance-id] - notice - Starting new instance of type 'tester-service' with instance ID '[instance-id]'.
|
|
92
|
+
[timestamp]: [instance-id] - notice - Starting new instance of type 'ti-tester-service' with instance ID '[instance-id]'.
|
|
86
93
|
[timestamp]: [instance-id] - alert - Error detected in the instance startup script!
|
|
87
94
|
```
|
|
88
95
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Finally, you should see a couple of execution statements with their results in JSON format.
|
|
96
|
+
Finally, you should see a sequence of test execution statements with their results in JSON format. These are the results of three business service calls that are part of the default tester microservice. The final `NOTICE` should indicate that all three tests have been completed successfully.
|
|
92
97
|
|
|
93
98
|
You can now kill the node process which should show you the following two lines:
|
|
94
99
|
|
|
95
100
|
```text
|
|
96
|
-
[timestamp]: [instance-id] - notice -
|
|
101
|
+
[timestamp]: [instance-id] - notice - [signal-code] event detected in main instance process.
|
|
97
102
|
[timestamp]: [instance-id] - notice - Instance '[instance-id]' shut down successfully.
|
|
98
103
|
```
|
|
99
104
|
|
|
100
|
-
The framework will always try to capture the shut-down event and log it
|
|
105
|
+
The framework will always try to capture the shut-down event and log it with the correct `[signal-code]`. This should work even in a container environment, but it might depend on your setup whether the last two entries will reach the logging system or not.
|
|
101
106
|
|
|
102
107
|
The tester module gets its starting configuration from an `.env` file included in the package. You can find more information about it later in the [Creating a microservice](#creating-a-microservice) section.
|
|
103
108
|
|
|
104
|
-
Before moving on, also take a good look at the file `bin/start-instance.js`. It should give you an idea
|
|
109
|
+
Before moving on, also take a good look at the file `bin/start-instance.js`. It should give you an idea of how the process of starting and stopping a microservice operates. In most cases this file should be enough as a starting script for your **ti-engine** based microservice applications. You can, of course, create your own starting script, but then you'll have to consider all necessary steps to properly handle the microservice instance.
|
|
105
110
|
|
|
106
111
|
## Architecture
|
|
107
112
|
|
|
@@ -117,46 +122,46 @@ See the following sections for more information on each of them.
|
|
|
117
122
|
|
|
118
123
|
### Tier 1 - Message exchange
|
|
119
124
|
|
|
120
|
-
This is the lowest framework tier, unless we count the actual data objects processed by the framework. As you already know, the foundational **ti-engine** concept is that of a messaging system. Therefore, the first tier provides an abstraction over a chosen message broker (Redis by default). That abstraction makes it easy to switch between message brokers whenever you want to without having to change anything above tier 1. It also provides several
|
|
125
|
+
This is the lowest framework tier, unless we count the actual data objects processed by the framework. As you already know, the foundational **ti-engine** concept is that of a messaging system. Therefore, the first tier provides an abstraction over a chosen message broker (Redis by default). That abstraction makes it easy to switch between message brokers whenever you want to without having to change anything above tier 1. It also provides several bonuses that can speed up your work—message encryption, message tracing, message observers, and others. More details about each of these features will be covered in the section [Using the framework](#using-the-framework).
|
|
121
126
|
|
|
122
|
-
Another important aspect for you to remember is that the message exchange is entirely _asynchronous_. This helps reduce system load and optimizes the usage of the available resources. Even so each node.js process can handle a limited
|
|
127
|
+
Another important aspect for you to remember is that the message exchange is entirely _asynchronous_. This helps reduce the system load and optimizes the usage of the available resources. Even so, each node.js process can handle a limited load. Therefore, you should plan for running multiple identical senders and receives to scale your solution. But more on that later.
|
|
123
128
|
|
|
124
129
|
For now, take a look at the following diagram:
|
|
125
130
|
|
|
126
|
-

|
|
131
|
+

|
|
127
132
|
|
|
128
|
-
It shows the standard flow of a message exchange between one sender and _n_ identical message receivers. The sender splits each message into an _envelope_ and a _payload_, then stores the payload in the shared cache and enqueues the envelope in the requests (destination) queue. Receivers can subscribe to that queue
|
|
133
|
+
It shows the standard flow of a message exchange between one sender and _n_ identical message receivers. The sender splits each message into an _envelope_ and a _payload_, then stores the payload in the shared cache and enqueues the envelope in the requests (destination) queue. Receivers can subscribe to that queue to fetch enqueued messages and process their contents. During the fetch sequence a receiver assembles the full message by getting the payload from the storage. This process is depicted by the blue flow lines.
|
|
129
134
|
|
|
130
|
-
After the processing is done the message payload is modified and the receiver sends the message back to the original sender using the same mechanism. It again splits the message into an envelope and a payload, stores the payload in the storage and enqueues the envelope in the sender response (source) queue. The sender will then assemble the message back and process the contained results. This process is depicted by the red flow lines.
|
|
135
|
+
After the processing is done, the message payload is modified, and the receiver sends the message back to the original sender using the same mechanism. It again splits the message into an envelope and a payload, stores the payload in the storage and enqueues the envelope in the sender response (source) queue. The sender will then assemble the message back and process the contained results. This process is depicted by the red flow lines.
|
|
131
136
|
|
|
132
|
-
In this scenario the framework
|
|
137
|
+
In this scenario the framework uses _Redis lists_ as queues for the message envelopes and _Redis hash_ as message payload storage. The splitting between envelope and payload is done to avoid unnecessary transportation of potentially large volumes of operational data between the microservices. Other message brokers might use a slightly different approach, but they should still adhere to the same logical flow.
|
|
133
138
|
|
|
134
139
|
The modules associated with this tier are all located in the `components/exchange/` folder. This is a short list of some terminology used here and in the JDoc inside the sourcecode itself:
|
|
135
140
|
|
|
136
|
-
* Message
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
+
* Class `Message`: a message is the actual data object processed by the framework. It consists of two parts—an envelope containing service information and a payload containing the actual data to be processed.
|
|
142
|
+
* Class `MessageSender`: a sender a specialized connector that is responsible for sending a message on its way to its destination. It does not handle the actual dispatch and delivery.
|
|
143
|
+
* Class `MessageReceiver`: a receiver is a specialized connector that is responsible for receiving messages at a predefined destination.
|
|
144
|
+
* Class `MessageExchange`: the exchange is the actual message processing engine. It handles sending and receiving messages via preconfigured message senders and message receivers.
|
|
145
|
+
* Class `MessageObserver`: an observer is a custom event listener that can be used to react on message `sent` and `received` events.
|
|
141
146
|
|
|
142
147
|
### Tier 2 - Service domains
|
|
143
148
|
|
|
144
|
-
This tier focuses on hosting and executing the _business logic_ of your application. It
|
|
149
|
+
This tier focuses on hosting and executing the _business logic_ of your application. It consists of _business services_ that process input data and return the result of the processing as output data. The business services are grouped in _service domains_, which are in turn hosted inside stateless _microservices_ also named _service instances_. All microservices are based on the `ServiceInstance` class, which establishes the basic framework structure and provides the basic functionality for the microservice lifecycle. It should not be used directly, however. Instead, there are two child types of `ServiceInstance` in **ti-engine** that you should use to implement your solution:
|
|
145
150
|
|
|
146
|
-
*
|
|
147
|
-
*
|
|
151
|
+
* Class `ServiceConsumer`: consumers are service instances that can call business services in any connected and available service domain.
|
|
152
|
+
* Class `ServiceProvider`: providers are service instances that host and run a set of business services in a particular service domain. Every service provider is also a service consumer.
|
|
148
153
|
|
|
149
|
-
The various service instances in a solution represent a network of interconnected service domains that contain the business logic of your application. All business services exchange data via _service calls_ using abstract _service addresses_. These service calls are transported from one address in the microservice network to another via the underlying message exchange tier. This, however, is completely transparent to the service instances. In essence, tier 2 does not care about the actual data transportation method or protocol. You could in fact change
|
|
154
|
+
The various service instances in a solution represent a network of interconnected service domains that contain the business logic of your application. All business services exchange data via _service calls_ using abstract _service addresses_. These service calls are transported from one address in the microservice network to another via the underlying message exchange tier. This, however, is completely transparent to the service instances. In essence, tier 2 does not care about the actual data transportation method or protocol. You could, in fact, completely change the tier 1 approach without having to modify anything in your business logic and business flow.
|
|
150
155
|
|
|
151
|
-
This tier is the place to
|
|
156
|
+
This tier is the place to use any databases, file storages, integrations with other applications, scheduling jobs, and so on. In general, it should focus on executing any granular tasks that are essential to the backbone operation of your application. The business logic here should remain **stateless** and any user context should be provided at runtime to each invoked business service. We'll see more concrete examples for that later in the section [Using the framework](#using-the-framework).
|
|
152
157
|
|
|
153
158
|
### Tier 3 - Solution implementation
|
|
154
159
|
|
|
155
|
-
This tier comprises the actual implementation of your application. Its structure and behavior
|
|
160
|
+
This tier comprises the actual implementation of your application. Its structure and behavior depend entirely on your vision and business goals. There are still a couple of points that remain constant while using **ti-engine**:
|
|
156
161
|
|
|
157
|
-
* It needs to
|
|
158
|
-
* It needs to take care of any type of stateful behavior like user sessions or transactions
|
|
159
|
-
* It needs to act as the primary interface between users and your application thus handling access management and user interactions
|
|
162
|
+
* It needs to use the business logic defined in tier 2 by calling the business services.
|
|
163
|
+
* It needs to take care of any type of stateful behavior like user sessions or transactions.
|
|
164
|
+
* It needs to act as the primary interface between users and your application, thus handling access management and user interactions.
|
|
160
165
|
|
|
161
166
|
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
167
|
|
|
@@ -215,31 +220,31 @@ TI_INSTANCE_NAME=tester-service
|
|
|
215
220
|
TI_AUDITING_LOG_MIN_LEVEL=200
|
|
216
221
|
```
|
|
217
222
|
|
|
218
|
-
The ENV initialization file provides the minimal settings for the proper tester microservice operation. The first three are usually _mandatory_ for every microservice you create while the last is provided for the needs of the tester demonstration. Let's review them and see what they do:
|
|
223
|
+
The ENV initialization file provides the minimal settings for the proper tester microservice operation. The first three are usually _mandatory_ for every microservice you create, while the last is provided for the needs of the tester demonstration. Let's review them and see what they do:
|
|
219
224
|
|
|
220
|
-
* `TI_INSTANCE_CLASS` 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.
|
|
221
|
-
* `TI_INSTANCE_CONFIG` specifies the relative path to the configuration data for the microservice. We'll delve into the specific settings below. 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.
|
|
222
|
-
* `TI_INSTANCE_NAME` is 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.
|
|
223
|
-
* `TI_AUDITING_LOG_MIN_LEVEL` specifies the minimum log level that should be sent to the log output stream. With a setting of `200` (corresponding to INFO) we filter out all `DEFAULT(0)` and `DEBUG(100)` entries as we don't need them for the
|
|
225
|
+
* `TI_INSTANCE_CLASS` 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.
|
|
226
|
+
* `TI_INSTANCE_CONFIG` specifies the relative path to the configuration data for the microservice. We'll delve into the specific settings below. 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.
|
|
227
|
+
* `TI_INSTANCE_NAME` is 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.
|
|
228
|
+
* `TI_AUDITING_LOG_MIN_LEVEL` specifies the minimum log level that should be sent to the log output stream. With a setting of `200` (corresponding to INFO) we filter out all `DEFAULT(0)` and `DEBUG(100)` entries as we don't need them for the tester microservice.
|
|
224
229
|
|
|
225
230
|
You can find the full list of available ENV variables and what they do below in [Using the framework](#using-the-framework) section.
|
|
226
231
|
|
|
227
|
-
#### Application
|
|
232
|
+
#### Application-specific files
|
|
228
233
|
|
|
229
234
|
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
235
|
|
|
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.
|
|
236
|
+
* 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
237
|
* 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.
|
|
233
238
|
* 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.
|
|
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.
|
|
239
|
+
* 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 a more practical situation, however, these calls would be directed towards other service domains.
|
|
235
240
|
|
|
236
|
-
The file `tester-service.json` contains framework configuration for the tester microservice. It will be automatically loaded inside the `ServiceInstance` class during initialization and will already be available inside the `onStart` method for usage. In this case the configuration is related to the two business services that will be provided by the microservice. More on this topic will be covered in section [Using the framework](#using-the-framework). For now
|
|
241
|
+
The file `tester-service.json` contains framework configuration for the tester microservice. It will be automatically loaded inside the `ServiceInstance` class during initialization and will already be available inside the `onStart` method for usage. In this case the configuration is related to the two business services that will be provided by the microservice. More on this topic will be covered in the section [Using the framework](#using-the-framework). For now pay attention to the `serviceFile` parameter and that it once again provides a relative path to the actual file containing the business logic.
|
|
237
242
|
|
|
238
|
-
The final two files are located in `bin/services/v1/` folder. They contain the definitions and business logic of the two business services that will be loaded at initialization time and provided by the tester microservice. In this case `service1.js` contains a
|
|
243
|
+
The final two files are located in `bin/services/v1/` folder. They contain the definitions and business logic of the two business services that will be loaded at initialization time and provided by the tester microservice. In this case `service1.js` contains a basic service that returns the current timestamp. The `service2.js` file contains a slightly more complex example of a service calling another service (in this case `service1`) before also returning two timestamps taken at the beginning and end of execution. Pay attention to the way the methods inside are declared and exported as this is the proper way to do this while using the **ti-engine** framework. Once again, we'll delve into the details and specifics of creating business services in the section [Using the framework](#using-the-framework).
|
|
239
244
|
|
|
240
245
|
### Creating your own microservice
|
|
241
246
|
|
|
242
|
-
Now that we've seen the structure of the tester microservice, let's create a new one and make it call `service2`. Let's use
|
|
247
|
+
Now that we've seen the structure of the tester microservice, let's create a new one and make it call `service2`. Let's use the same file structure as for the tester. Create a folder `my-service` and in it create a `package.json` file. Make sure to include a dependency to `"@ti-engine/core": "latest"` in it. After that create a `.env` file and add the following entries in it:
|
|
243
248
|
|
|
244
249
|
```text
|
|
245
250
|
TI_INSTANCE_CLASS=bin/my-service.js
|
|
@@ -258,7 +263,7 @@ class MyService extends ServiceConsumer {}
|
|
|
258
263
|
module.exports = MyService;
|
|
259
264
|
```
|
|
260
265
|
|
|
261
|
-
|
|
266
|
+
Remember to also export your new class at the end, otherwise the framework won't be able to initialize it.
|
|
262
267
|
|
|
263
268
|
To make use of all the inherited features of the `ServiceConsumer` class we have to add a `constructor` that invokes the base one in the parent class:
|
|
264
269
|
|
|
@@ -274,7 +279,7 @@ class MyService extends ServiceConsumer {
|
|
|
274
279
|
module.exports = MyService;
|
|
275
280
|
```
|
|
276
281
|
|
|
277
|
-
And now let's add a service call
|
|
282
|
+
And now let's add a service call executed at microservice start after `500` milliseconds timeout:
|
|
278
283
|
|
|
279
284
|
```js
|
|
280
285
|
const ServiceConsumer = require( "@ti-engine/core/service-consumer" );
|
|
@@ -311,7 +316,7 @@ class MyService extends ServiceConsumer {
|
|
|
311
316
|
module.exports = MyService;
|
|
312
317
|
```
|
|
313
318
|
|
|
314
|
-
Now let's start the new microservice with `node .\node_modules\@ti-engine\core\bin\start-instance.js` command. Remember, you need to execute this inside the `my-service` folder you created for this exercise. If everything was configured correctly you should get the following output:
|
|
319
|
+
Now let's start the new microservice with `node .\node_modules\@ti-engine\core\bin\start-instance.js` command. Remember, you need to execute this inside the `my-service` folder you created for this exercise. If everything was configured correctly, you should get the following output:
|
|
315
320
|
|
|
316
321
|
```text
|
|
317
322
|
[timestamp]: [instance-id] - notice - Starting new instance of type 'my-service' with instance ID '[instance-id]'.
|
|
@@ -322,7 +327,7 @@ Now let's start the new microservice with `node .\node_modules\@ti-engine\core\b
|
|
|
322
327
|
|
|
323
328
|
If you haven't started anything else, this is all you should see at this point.
|
|
324
329
|
|
|
325
|
-
Now without exiting this node process let's start the original tester microservice as well. Once it initializes and does its work take a look at the output logs of the `my-service` process:
|
|
330
|
+
Now without exiting this node process, let's start the original tester microservice as well. Once it initializes and does its work take a look at the output logs of the `my-service` process:
|
|
326
331
|
|
|
327
332
|
```text
|
|
328
333
|
...
|
|
@@ -332,19 +337,19 @@ Now without exiting this node process let's start the original tester microservi
|
|
|
332
337
|
» {"nodeVersion":[node-version]}
|
|
333
338
|
```
|
|
334
339
|
|
|
335
|
-
This means the service call processing was successful and result was returned to `my-service`. Because we made the receiving of the result blocking and part of the initialization sequence, the new microservice did not report successful startup until it received that response from `ti-tester-service`.
|
|
340
|
+
This means the service call processing was successful and a result was returned to `my-service`. Because we made the receiving of the result blocking and part of the initialization sequence, the new microservice did not report successful startup until it received that response from `ti-tester-service`.
|
|
336
341
|
|
|
337
|
-
And with this step we are done. The new microservice is now operational. You can continue to tweak and play with it
|
|
342
|
+
And with this step we are done. The new microservice is now operational. You can continue to tweak and play with it to understand better how it all works. For more details on the **ti-engine** inner working, please see the following sections.
|
|
338
343
|
|
|
339
344
|
## Using the framework
|
|
340
345
|
|
|
341
346
|
### Environment variables
|
|
342
347
|
|
|
343
|
-
These are the system-level ENV variables that can be used to configure the framework. Use
|
|
348
|
+
These are the system-level ENV variables that can be used to configure the framework. Use an `.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
349
|
|
|
345
350
|
TI_AUDITING_LOG_MIN_LEVEL
|
|
346
351
|
: 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).
|
|
352
|
+
: Specifies the minimum log level that should be sent to the log output stream. The framework will filter out all log entries with a level below this value. The default value is `200` (corresponding to INFO).
|
|
348
353
|
|
|
349
354
|
TI_FAIL_FAST_ON_UNHANDLED_OFF
|
|
350
355
|
: Type: Optional
|
|
@@ -352,39 +357,39 @@ TI_FAIL_FAST_ON_UNHANDLED_OFF
|
|
|
352
357
|
|
|
353
358
|
TI_INSTANCE_CLASS
|
|
354
359
|
: 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.
|
|
360
|
+
: 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
361
|
|
|
357
362
|
TI_INSTANCE_CONFIG
|
|
358
363
|
: 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.
|
|
364
|
+
: 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
365
|
|
|
361
366
|
TI_INSTANCE_NAME
|
|
362
367
|
: 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.
|
|
368
|
+
: 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
369
|
|
|
365
370
|
### Framework settings
|
|
366
371
|
|
|
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
|
|
372
|
+
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 startup.
|
|
368
373
|
|
|
369
374
|
AUDITING_LOG_CONSOLE_ENABLED
|
|
370
375
|
: JSON path `auditing.logConsoleEnabled`, type `boolean`, default `true`
|
|
371
376
|
: ENV variable `TI_AUDITING_LOG_CONSOLE_ENABLED`
|
|
372
|
-
: This setting controls whether the `auditing` module will send the log entries to the OS console or not. In some cases, like Cloud environments, you might want to disable this, especially if the OS console is not made available. This functions independently of other logging outputs like for example GCloud error reporting.
|
|
377
|
+
: This setting controls whether the `auditing` module will send the log entries to the OS console or not. In some cases, like Cloud environments, you might want to disable this, especially if the OS console is not made available. This functions independently of other logging outputs like, for example, GCloud error reporting.
|
|
373
378
|
|
|
374
379
|
AUDITING_LOG_DETAILS
|
|
375
380
|
: JSON path `auditing.logDetails`, type `boolean`, default `true`
|
|
376
381
|
: ENV variable `TI_AUDITING_LOG_DETAILS`
|
|
377
|
-
: This setting controls whether the `auditing` module will include the log entry details (located in the `data` property) in the final log output. You might want to disable this if you want a leaner log output or the log entry details are not something you plan to use for analysis later.
|
|
382
|
+
: This setting controls whether the `auditing` module will include the log entry details (located in the `data` property) in the final log output. You might want to disable this if you want a leaner log output, or the log entry details are not something you plan to use for analysis later.
|
|
378
383
|
|
|
379
384
|
AUDITING_LOG_MIN_LEVEL
|
|
380
385
|
: JSON path `auditing.logMinLevel`, type `number`, default `0`
|
|
381
386
|
: ENV variable `TI_AUDITING_LOG_MIN_LEVEL`
|
|
382
|
-
: This setting controls the minimum log severity level that the framework will log in the log output. You can and should set this to `200` (INFO) for production environments
|
|
387
|
+
: This setting controls the minimum log severity level that the framework will log in the log output. You can and should set this to `200` (INFO) for production environments to filter out the DEBUG and the low-level DEFAULT entries.
|
|
383
388
|
|
|
384
389
|
AUDITING_LOG_USES_JSON
|
|
385
390
|
: JSON path `auditing.logUsesJSON`, type `boolean`, default `false`
|
|
386
391
|
: ENV variable `TI_AUDITING_LOG_USES_JSON`
|
|
387
|
-
: This setting controls whether the log entries would be sent to output formatted as JSONs or not. By default, the framework outputs log entries as prettified text. In some cases however you might want to have the entire entry as a JSON for further processing (for example if you're sending all logs to Elasticsearch).
|
|
392
|
+
: This setting controls whether the log entries would be sent to output formatted as JSONs or not. By default, the framework outputs log entries as prettified text. In some cases, however, you might want to have the entire entry as a JSON for further processing (for example, if you're sending all logs to Elasticsearch).
|
|
388
393
|
|
|
389
394
|
GCLOUD_API_KEY (Alpha)
|
|
390
395
|
: JSON path `gcloudIntegration.apiKey`
|
|
@@ -397,7 +402,7 @@ GCLOUD_PROJECT_ID (Alpha)
|
|
|
397
402
|
LOCALIZATION_LABELS_PATH
|
|
398
403
|
: JSON path `localization.labelsPath`, type `Array<string>`, default `[]`
|
|
399
404
|
: ENV variable `TI_LOCALIZATION_LABELS_PATH`
|
|
400
|
-
: This setting holds a list of paths to custom `.json` files containing additional localization information. By default, the framework also provides such a file with
|
|
405
|
+
: This setting holds a list of paths to custom `.json` files containing additional localization information. By default, the framework also provides such a file with English texts that can be customized further. All additional JSONs in these files have to follow the rules and structure of the `localization` module. The ENV variable currently supports providing only a single custom path.
|
|
401
406
|
|
|
402
407
|
LOCALIZATION_LANGUAGE
|
|
403
408
|
: JSON path `localization.language`, type `string`, default `en`
|
|
@@ -407,12 +412,12 @@ LOCALIZATION_LANGUAGE
|
|
|
407
412
|
MEMORY_CACHE_AUTH_KEY
|
|
408
413
|
: JSON path `memoryCache.authKey`, type `string`, default `undefined`
|
|
409
414
|
: ENV variable `TI_MEMORY_CACHE_AUTH_KEY`
|
|
410
|
-
: This setting holds the Redis password for accessing the Redis server if such password is required.
|
|
415
|
+
: This setting holds the Redis password for accessing the Redis server if such a password is required.
|
|
411
416
|
|
|
412
417
|
MEMORY_CACHE_REDIS_DB
|
|
413
418
|
: JSON path `memoryCache.redisDB`, type `number`, default `0`
|
|
414
419
|
: ENV variable `TI_MEMORY_CACHE_REDIS_DB`
|
|
415
|
-
: This setting specifies the Redis DB to be used for all operations. When setting this make sure that the Redis server actually supports multiple DBs (for example Redis Cloud has only one DB with ID `0`).
|
|
420
|
+
: This setting specifies the Redis DB to be used for all operations. When setting this make sure that the Redis server actually supports multiple DBs (for example, Redis Cloud has only one DB with ID `0`).
|
|
416
421
|
|
|
417
422
|
MEMORY_CACHE_REDIS_HOST
|
|
418
423
|
: JSON path `memoryCache.redisHost`, type `string`, default `127.0.0.1`
|
|
@@ -427,7 +432,7 @@ MEMORY_CACHE_REDIS_PORT
|
|
|
427
432
|
MEMORY_CACHE_RETRY_MAX_ATTEMPTS
|
|
428
433
|
: JSON path `memoryCache.retryMaxAttempts`, type `number`, default `undefined`
|
|
429
434
|
: 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.
|
|
435
|
+
: This setting holds the maximum number of attempts to (re)connect to the Redis server. By default, there is no limit.
|
|
431
436
|
|
|
432
437
|
MEMORY_CACHE_RETRY_MAX_INTERVAL
|
|
433
438
|
: JSON path `memoryCache.retryMaxInterval`, type `number`, default `1000`
|
|
@@ -450,12 +455,12 @@ MESSAGE_EXCHANGE_MESSAGE_STORE (Advanced)
|
|
|
450
455
|
MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED (Advanced)
|
|
451
456
|
: JSON path `messageExchange.securityHashEnabled`, type `boolean`, default `true`
|
|
452
457
|
: ENV variable `TI_MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED`
|
|
453
|
-
: This setting controls whether the message exchange will use a control hash mechanism to ensure there is no tampering with the messages in between service calls. In most cases you would want to keep this enabled since it ensures the integrity of your data. If you are concerned about performance (hashing with `blake2` is
|
|
458
|
+
: This setting controls whether the message exchange will use a control hash mechanism to ensure there is no tampering with the messages in between service calls. In most cases you would want to keep this enabled since it ensures the integrity of your data. If you are concerned about performance (hashing with `blake2` is rapid, but it still eats some milliseconds) you might want to try and disable this to see if it makes any notable difference.
|
|
454
459
|
|
|
455
460
|
MESSAGE_EXCHANGE_SECURITY_HASH_KEY (Advanced)
|
|
456
461
|
: JSON path `messageExchange.securityHashKey`, type `string`, default `random uuid`
|
|
457
462
|
: ENV variable `TI_MESSAGE_EXCHANGE_SECURITY_HASH_KEY`
|
|
458
|
-
: This setting holds the encryption key used by the message exchange control hash mechanism. By default, this has a random uuid value that can be used for development
|
|
463
|
+
: This setting holds the encryption key used by the message exchange control hash mechanism. By default, this has a random uuid value that can be used for development only. For production environments you absolutely must provide your own encryption key via the ENV variable. Depending on your configuration and infrastructure, it might come from a secure storage, HSM, key vault, etc.
|
|
459
464
|
|
|
460
465
|
MESSAGE_EXCHANGE_TRACE_EXPIRATION_TIME
|
|
461
466
|
: JSON path `messageExchange.traceExpirationTime`, type `number`, default `3600`
|
|
@@ -464,7 +469,7 @@ MESSAGE_EXCHANGE_TRACE_EXPIRATION_TIME
|
|
|
464
469
|
MESSAGE_EXCHANGE_TRACE_LOG_ENABLED
|
|
465
470
|
: JSON path `messageExchange.traceLogEnabled`, type `boolean`, default `false`
|
|
466
471
|
: ENV variable `TI_MESSAGE_EXCHANGE_TRACE_LOG_ENABLED`
|
|
467
|
-
: This setting controls whether the `auditing` module should output all trace messages as normal log entries or not. Normally, you don't want that since it will clutter the standard log quite a lot. All traces go their own storage and can be reviewed and processed separately from the log entries. In some cases, however, as in debugging, enabling this can help you identify hard to track problem.
|
|
472
|
+
: This setting controls whether the `auditing` module should output all trace messages as normal log entries or not. Normally, you don't want that since it will clutter the standard log quite a lot. All traces go to their own storage and can be reviewed and processed separately from the log entries. In some cases, however, as in debugging, enabling this can help you identify a hard to track problem.
|
|
468
473
|
|
|
469
474
|
MESSAGE_EXCHANGE_TRACE_REPOSITORY (Advanced)
|
|
470
475
|
: JSON path `messageExchange.traceRepository`, type `string`, default `ti:messages:trace`
|
|
@@ -488,7 +493,7 @@ SERVICE_HEALTH_CHECK_TIMEOUT (Advanced)
|
|
|
488
493
|
|
|
489
494
|
SERVICE_REGISTRY_ADDRESS (Advanced)
|
|
490
495
|
: JSON path `serviceConfig.serviceRegistryAddress`, type `string`, default `ti:services:registry:catalog:`
|
|
491
|
-
: This setting holds the prefix of the Redis key name used as business service registry. If the microservice is a `ServiceProvider`, on start up it will register its business service portfolio in that Redis set. Also, on each service call that same registry will be searched for the existence of the called business service. This is not something you should modify unless you are making a customized implementation of the tier 1 architectural layer.
|
|
496
|
+
: This setting holds the prefix of the Redis key name used as a business service registry. If the microservice is a `ServiceProvider`, on start up it will register its business service portfolio in that Redis set. Also, on each service call that same registry will be searched for the existence of the called business service. This is not something you should modify unless you are making a customized implementation of the tier 1 architectural layer.
|
|
492
497
|
|
|
493
498
|
OPERATION_MODE
|
|
494
499
|
: JSON path `operationMode`, type `string`, default `production`
|
|
@@ -187,7 +187,7 @@ class ServiceCallProcessor {
|
|
|
187
187
|
} ).catch( ( error ) => {
|
|
188
188
|
clearTimeout( this.#timeoutHandle );
|
|
189
189
|
this.#isProcessed = true;
|
|
190
|
-
logger.log( `Error during service call execution!`, logger.logSeverity.
|
|
190
|
+
logger.log( `Error during service call execution!`, logger.logSeverity.DEBUG, error );
|
|
191
191
|
return {
|
|
192
192
|
isSuccessful: false,
|
|
193
193
|
exception: exceptions.raise( error ),
|
|
@@ -32,9 +32,9 @@ class ServiceConsumer extends ServiceInstance {
|
|
|
32
32
|
/**
|
|
33
33
|
* @constructor
|
|
34
34
|
* @param {string} serviceDomainName The service domain name for this service instance.
|
|
35
|
-
* @param {
|
|
35
|
+
* @param {ServiceConfiguration} [serviceConfig] The JSON configuration for this service.
|
|
36
36
|
*/
|
|
37
|
-
constructor( serviceDomainName, serviceConfig
|
|
37
|
+
constructor( serviceDomainName, serviceConfig ) {
|
|
38
38
|
super( serviceDomainName, serviceConfig );
|
|
39
39
|
|
|
40
40
|
// make sure this abstract class cannot be instantiated:
|
|
@@ -17,7 +17,7 @@ const messageDispatcher = require( "#message-dispatcher" );
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* @typedef {Object} ServiceConfiguration
|
|
20
|
-
* @property {ServiceDefinition[]} services A list of service definitions to be registered with the {@link ServiceProvider}.
|
|
20
|
+
* @property {ServiceDefinition[]} [services] A list of service definitions to be registered with the {@link ServiceProvider}.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -42,9 +42,9 @@ class ServiceInstance {
|
|
|
42
42
|
/**
|
|
43
43
|
* @constructor
|
|
44
44
|
* @param {string} serviceDomainName The service domain name for this service instance.
|
|
45
|
-
* @param {
|
|
45
|
+
* @param {ServiceConfiguration} [serviceConfig={ services: [] }] The JSON configuration for this service.
|
|
46
46
|
*/
|
|
47
|
-
constructor( serviceDomainName, serviceConfig = {} ) {
|
|
47
|
+
constructor( serviceDomainName, serviceConfig = { services: [] } ) {
|
|
48
48
|
// Ensure this abstract class cannot be instantiated:
|
|
49
49
|
if ( new.target === ServiceInstance ) {
|
|
50
50
|
throw exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_CLASS_INIT, { name: this.constructor.name } );
|
|
@@ -37,9 +37,9 @@ class ServiceProvider extends ServiceConsumer {
|
|
|
37
37
|
/**
|
|
38
38
|
* @constructor
|
|
39
39
|
* @param {string} serviceDomainName The service domain name for this service instance.
|
|
40
|
-
* @param {
|
|
40
|
+
* @param {ServiceConfiguration} [serviceConfig] The JSON configuration for this service.
|
|
41
41
|
*/
|
|
42
|
-
constructor( serviceDomainName, serviceConfig
|
|
42
|
+
constructor( serviceDomainName, serviceConfig ) {
|
|
43
43
|
super( serviceDomainName, serviceConfig );
|
|
44
44
|
|
|
45
45
|
// make sure this abstract class cannot be instantiated:
|
|
@@ -118,7 +118,7 @@ class RedisClient {
|
|
|
118
118
|
/* Public interface */
|
|
119
119
|
|
|
120
120
|
/**
|
|
121
|
-
* Used to return the Redis client identifier.
|
|
121
|
+
* Used to return the Redis client identifier assigned internally.
|
|
122
122
|
*
|
|
123
123
|
* @property
|
|
124
124
|
* @returns {string}
|
|
@@ -129,7 +129,7 @@ class RedisClient {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
|
-
* Used to return the
|
|
132
|
+
* Used to return the client ID assigned by the Redis server.
|
|
133
133
|
*
|
|
134
134
|
* @property
|
|
135
135
|
* @returns {number}
|
|
@@ -195,9 +195,9 @@ class RedisClient {
|
|
|
195
195
|
// Fetch the server information and store it:
|
|
196
196
|
return this.#fetchServerInfo();
|
|
197
197
|
} ).then( () => {
|
|
198
|
-
return this.#
|
|
198
|
+
return this.#getClientID();
|
|
199
199
|
} ).then( ( clientID ) => {
|
|
200
|
-
// Store the
|
|
200
|
+
// Store the connection ID:
|
|
201
201
|
this.#redisClientID = clientID;
|
|
202
202
|
resolve();
|
|
203
203
|
} ).catch( ( error ) => {
|
|
@@ -476,10 +476,12 @@ class RedisClient {
|
|
|
476
476
|
|
|
477
477
|
this.#redisConnection.once( "ready", () => {
|
|
478
478
|
this.#clientStatus = clientStatusEnum.CONNECTED;
|
|
479
|
+
logger.log( `Connection to Redis server '${ this.#redisConnection.options.host }:${ this.#redisConnection.options.port }' established by client '${ this.identifier }' and is ready to be used.`, logger.logSeverity.INFO );
|
|
479
480
|
this.#notifyConnectionObservers();
|
|
480
481
|
|
|
481
482
|
this.#redisConnection.on( "ready", () => {
|
|
482
483
|
this.#clientStatus = clientStatusEnum.CONNECTED;
|
|
484
|
+
logger.log( `Connection to Redis server '${ this.#redisConnection.options.host }:${ this.#redisConnection.options.port }' reestablished by client '${ this.identifier }' and is ready to be used.`, logger.logSeverity.INFO );
|
|
483
485
|
this.#notifyConnectionObservers();
|
|
484
486
|
} );
|
|
485
487
|
|
|
@@ -515,14 +517,13 @@ class RedisClient {
|
|
|
515
517
|
*/
|
|
516
518
|
#notifyConnectionObservers() {
|
|
517
519
|
// Notify all connection observers about the event:
|
|
518
|
-
_.forEach( this.#connectionObservers, (
|
|
520
|
+
_.forEach( this.#connectionObservers, ( connectionObserver ) => {
|
|
519
521
|
if ( this.#clientStatus === clientStatusEnum.CONNECTED ) {
|
|
520
|
-
|
|
521
|
-
connectionObservers.onConnectionRecovered( this.#clientIdentifier );
|
|
522
|
+
connectionObserver.onConnectionRecovered( this.#clientIdentifier );
|
|
522
523
|
} else if ( this.#clientStatus === clientStatusEnum.DISRUPTED ) {
|
|
523
|
-
|
|
524
|
+
connectionObserver.onConnectionDisrupted( this.#clientIdentifier );
|
|
524
525
|
} else if ( this.#clientStatus === clientStatusEnum.DISCONNECTED ) {
|
|
525
|
-
|
|
526
|
+
connectionObserver.onConnectionLost( this.#clientIdentifier );
|
|
526
527
|
}
|
|
527
528
|
} );
|
|
528
529
|
}
|
|
@@ -574,7 +575,7 @@ class RedisClient {
|
|
|
574
575
|
* @returns {Promise<number>}
|
|
575
576
|
* @private
|
|
576
577
|
*/
|
|
577
|
-
#
|
|
578
|
+
#getClientID() {
|
|
578
579
|
let commandArguments = [ "client", "id" ];
|
|
579
580
|
return this.callCommand( commandArguments ).then( ( clientID ) => Number( clientID ) );
|
|
580
581
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ti-engine/core",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.5",
|
|
4
4
|
"description": "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.",
|
|
5
5
|
"author": "Boris Kostadinov <kostadinov.boris@gmail.com>",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|