@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
|
@@ -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 MessageObserver = require( "#message-observer" );
|
|
7
10
|
const tools = require( "#tools" );
|
|
@@ -92,7 +95,7 @@ class ServiceCaller extends MessageObserver {
|
|
|
92
95
|
this.#findServiceInRegistry( serviceAddress ).then( () => {
|
|
93
96
|
return this.#prepareServiceCall( serviceAddress, serviceParams, serviceExecContext );
|
|
94
97
|
} ).then( ( serviceCall ) => {
|
|
95
|
-
return messageDispatcher.sendRequest( serviceCall );
|
|
98
|
+
return messageDispatcher.instance.sendRequest( serviceCall );
|
|
96
99
|
} ).then( ( messageID ) => {
|
|
97
100
|
this.#addTaskHandler( messageID, ( serviceCall ) => {
|
|
98
101
|
this.#completeServiceCall( serviceCall ).then( ( serviceCall ) => {
|
|
@@ -184,7 +187,7 @@ class ServiceCaller extends MessageObserver {
|
|
|
184
187
|
#findServiceInRegistry( serviceAddress ) {
|
|
185
188
|
return new Promise( ( resolve, reject ) => {
|
|
186
189
|
let serviceCatalog = config.getSetting( config.setting.SERVICE_REGISTRY_ADDRESS ) + serviceAddress.serviceDomainName;
|
|
187
|
-
cache.isSetMember( serviceCatalog, serviceAddress.serviceAlias ).then( ( result ) => {
|
|
190
|
+
cache.instance.isSetMember( serviceCatalog, serviceAddress.serviceAlias ).then( ( result ) => {
|
|
188
191
|
if ( result === true ) {
|
|
189
192
|
resolve();
|
|
190
193
|
} else {
|
|
@@ -207,7 +210,7 @@ class ServiceCaller extends MessageObserver {
|
|
|
207
210
|
* @private
|
|
208
211
|
*/
|
|
209
212
|
#prepareServiceCall( serviceAddress, serviceParams, serviceExecContext ) {
|
|
210
|
-
return new Promise( ( resolve
|
|
213
|
+
return new Promise( ( resolve ) => {
|
|
211
214
|
const ServiceInstance = require( "#service-instance" );
|
|
212
215
|
|
|
213
216
|
// assemble the new service call:
|
|
@@ -255,7 +258,7 @@ class ServiceCaller extends MessageObserver {
|
|
|
255
258
|
* @private
|
|
256
259
|
*/
|
|
257
260
|
#completeServiceCall( serviceCall ) {
|
|
258
|
-
return new Promise( ( resolve
|
|
261
|
+
return new Promise( ( resolve ) => {
|
|
259
262
|
serviceCall.finishedOn = Date.now();
|
|
260
263
|
serviceCall.executionTime = serviceCall.finishedOn - serviceCall.createdOn;
|
|
261
264
|
serviceCall.isCompleted = true;
|
|
@@ -303,4 +306,4 @@ class ServiceCaller extends MessageObserver {
|
|
|
303
306
|
|
|
304
307
|
}
|
|
305
308
|
|
|
306
|
-
module.exports = ServiceCaller;
|
|
309
|
+
module.exports = ServiceCaller;
|
|
@@ -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 ServiceInstance = require( "#service-instance" );
|
|
7
10
|
const exceptions = require( "#exceptions" );
|
|
@@ -10,7 +13,7 @@ const messageDispatcher = require( "#message-dispatcher" );
|
|
|
10
13
|
/**
|
|
11
14
|
* Abstract class used to define a Service Consumer behavior.
|
|
12
15
|
* <br/>
|
|
13
|
-
* NOTE: Inherit this to create
|
|
16
|
+
* NOTE: Inherit this to create a module that can be started as a microservice consumer instance.
|
|
14
17
|
* <br/>
|
|
15
18
|
* NOTE: A service consumer is a microservice that can invoke named business services in the APIs of other
|
|
16
19
|
* microservices using {@link ServiceCall} objects. The consumer does not need to know the specifics of
|
|
@@ -62,7 +65,7 @@ class ServiceConsumer extends ServiceInstance {
|
|
|
62
65
|
this.#serviceCaller = new ServiceCaller();
|
|
63
66
|
|
|
64
67
|
super.onStart().then( () => {
|
|
65
|
-
messageDispatcher.addMessageObserverResponsesIn( this.#serviceCaller );
|
|
68
|
+
messageDispatcher.instance.addMessageObserverResponsesIn( this.#serviceCaller );
|
|
66
69
|
resolve();
|
|
67
70
|
} ).catch( ( error ) => {
|
|
68
71
|
reject( exceptions.raise( error ) );
|
|
@@ -93,6 +96,22 @@ class ServiceConsumer extends ServiceInstance {
|
|
|
93
96
|
} );
|
|
94
97
|
}
|
|
95
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Used to report health status of the service instance for external monitoring.
|
|
101
|
+
* This is a scheduled job that will be executed at SERVICE_HEALTH_CHECK_INTERVAL time.
|
|
102
|
+
* <br/>
|
|
103
|
+
* NOTE: By default this method will update a Redis key with an expiration timer. You can override this
|
|
104
|
+
* functionality with something custom like calling an HTTP endpoint.
|
|
105
|
+
*
|
|
106
|
+
* @method
|
|
107
|
+
* @override
|
|
108
|
+
* @virtual
|
|
109
|
+
* @public
|
|
110
|
+
*/
|
|
111
|
+
reportHealthy() {
|
|
112
|
+
super.reportHealthy();
|
|
113
|
+
}
|
|
114
|
+
|
|
96
115
|
/**
|
|
97
116
|
* Used to invoke a business service in any {@link ServiceInstance}.
|
|
98
117
|
*
|
|
@@ -109,4 +128,4 @@ class ServiceConsumer extends ServiceInstance {
|
|
|
109
128
|
|
|
110
129
|
}
|
|
111
130
|
|
|
112
|
-
module.exports = ServiceConsumer;
|
|
131
|
+
module.exports = ServiceConsumer;
|
|
@@ -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 MessageObserver = require( "#message-observer" );
|
|
7
10
|
const ServiceInstance = require( "#service-instance" );
|
|
@@ -55,6 +58,8 @@ class ServiceExecutor extends MessageObserver {
|
|
|
55
58
|
#serviceInterface = {};
|
|
56
59
|
/** @type VerifyAccessMethod */
|
|
57
60
|
#verifyAccess;
|
|
61
|
+
#registrationTasks = {};
|
|
62
|
+
#registrationRetryInterval = 500;
|
|
58
63
|
|
|
59
64
|
/**
|
|
60
65
|
* @constructor
|
|
@@ -62,11 +67,12 @@ class ServiceExecutor extends MessageObserver {
|
|
|
62
67
|
constructor() {
|
|
63
68
|
super();
|
|
64
69
|
|
|
70
|
+
// Setup a default empty verify access method:
|
|
65
71
|
this.#verifyAccess = () => {
|
|
66
72
|
return Promise.resolve();
|
|
67
73
|
};
|
|
68
74
|
|
|
69
|
-
cache.addConnectionObserver( this );
|
|
75
|
+
cache.instance.addConnectionObserver( this );
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
/* Public interface */
|
|
@@ -78,7 +84,9 @@ class ServiceExecutor extends MessageObserver {
|
|
|
78
84
|
* @returns {ServiceInterface}
|
|
79
85
|
* @public
|
|
80
86
|
*/
|
|
81
|
-
get serviceInterface() {
|
|
87
|
+
get serviceInterface() {
|
|
88
|
+
return this.#serviceInterface;
|
|
89
|
+
}
|
|
82
90
|
|
|
83
91
|
/**
|
|
84
92
|
*
|
|
@@ -91,7 +99,7 @@ class ServiceExecutor extends MessageObserver {
|
|
|
91
99
|
*/
|
|
92
100
|
onMessage( identifier, message ) {
|
|
93
101
|
this.#processServiceCall( message ).then( ( serviceCall ) => {
|
|
94
|
-
return messageDispatcher.sendResponse( serviceCall );
|
|
102
|
+
return messageDispatcher.instance.sendResponse( serviceCall );
|
|
95
103
|
} ).catch( ( error ) => {
|
|
96
104
|
logger.log( `Failed to send service call response after processing! Service call ID was: '${ message.messageID }'`, logger.logSeverity.ERROR, error );
|
|
97
105
|
} );
|
|
@@ -120,17 +128,15 @@ class ServiceExecutor extends MessageObserver {
|
|
|
120
128
|
onConnectionRecovered( identifier ) {
|
|
121
129
|
super.onConnectionRecovered( identifier );
|
|
122
130
|
|
|
123
|
-
if ( identifier !== cache.connectionIdentifier ) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
} );
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
//TODO: Retry service registration after 0.5 seconds.
|
|
133
|
-
}
|
|
131
|
+
if ( identifier !== cache.instance.connectionIdentifier ) {
|
|
132
|
+
let serviceCatalog = config.getSetting( config.setting.SERVICE_REGISTRY_ADDRESS ) + ServiceInstance.serviceDomainName;
|
|
133
|
+
_.forOwn( this.#serviceInterface, ( versions, serviceAlias ) => {
|
|
134
|
+
if ( !this.#registrationTasks[ serviceAlias ] ) {
|
|
135
|
+
this.#registrationTasks[ serviceAlias ] = setInterval( () => {
|
|
136
|
+
this.#registerServiceToCatalog( serviceCatalog, serviceAlias );
|
|
137
|
+
}, this.#registrationRetryInterval );
|
|
138
|
+
}
|
|
139
|
+
} );
|
|
134
140
|
}
|
|
135
141
|
}
|
|
136
142
|
|
|
@@ -197,6 +203,25 @@ class ServiceExecutor extends MessageObserver {
|
|
|
197
203
|
};
|
|
198
204
|
}
|
|
199
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Used to register a service in the service registry.
|
|
208
|
+
*
|
|
209
|
+
* @method
|
|
210
|
+
* @param {string} serviceCatalog
|
|
211
|
+
* @param {string} serviceAlias
|
|
212
|
+
* @private
|
|
213
|
+
*/
|
|
214
|
+
#registerServiceToCatalog( serviceCatalog, serviceAlias ) {
|
|
215
|
+
if ( cache.instance.isOperational ) {
|
|
216
|
+
cache.instance.addToSet( serviceCatalog, serviceAlias ).then( () => {
|
|
217
|
+
clearTimeout( this.#registrationTasks[ serviceAlias ] );
|
|
218
|
+
delete this.#registrationTasks[ serviceAlias ];
|
|
219
|
+
} ).catch( ( error ) => {
|
|
220
|
+
logger.log( `Record for service '${ serviceAlias }' could not be added to the service registry. Will retry in '${ this.#registrationRetryInterval }' milliseconds.`, logger.logSeverity.ERROR, error );
|
|
221
|
+
} );
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
200
225
|
/**
|
|
201
226
|
* Used to process the actual service call.
|
|
202
227
|
*
|
|
@@ -206,7 +231,7 @@ class ServiceExecutor extends MessageObserver {
|
|
|
206
231
|
* @private
|
|
207
232
|
*/
|
|
208
233
|
#processServiceCall( serviceCall ) {
|
|
209
|
-
return new Promise( ( resolve
|
|
234
|
+
return new Promise( ( resolve ) => {
|
|
210
235
|
this.#verifyAccess( serviceCall.authToken, serviceCall.serviceAddress ).then( () => {
|
|
211
236
|
return this.#identifyService( serviceCall.serviceAddress );
|
|
212
237
|
} ).then( ( serviceHandler ) => {
|
|
@@ -253,4 +278,4 @@ class ServiceExecutor extends MessageObserver {
|
|
|
253
278
|
|
|
254
279
|
}
|
|
255
280
|
|
|
256
|
-
module.exports = ServiceExecutor;
|
|
281
|
+
module.exports = ServiceExecutor;
|
|
@@ -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 schedule = require( "node-schedule" );
|
|
@@ -21,8 +24,6 @@ const messageDispatcher = require( "#message-dispatcher" );
|
|
|
21
24
|
* Abstract class used to define a Service Instance behavior.
|
|
22
25
|
* <br/>
|
|
23
26
|
* NOTE: Inherit this to create a module that can be started as a microservice instance.
|
|
24
|
-
* <br/>
|
|
25
|
-
* NOTE: This class does not
|
|
26
27
|
*
|
|
27
28
|
* @class ServiceInstance
|
|
28
29
|
* @abstract
|
|
@@ -43,12 +44,22 @@ class ServiceInstance {
|
|
|
43
44
|
* @param {Object} [serviceConfig={}] The JSON configuration for this service.
|
|
44
45
|
*/
|
|
45
46
|
constructor( serviceDomainName, serviceConfig = {} ) {
|
|
46
|
-
//
|
|
47
|
+
// Ensure this abstract class cannot be instantiated:
|
|
47
48
|
if ( new.target === ServiceInstance ) {
|
|
48
49
|
throw exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_CLASS_INIT, { name: this.constructor.name } );
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
// Guard against multiple instances in a single process (not supported):
|
|
53
|
+
if ( ServiceInstance.#instanceID && ServiceInstance.#serviceDomainName ) {
|
|
54
|
+
throw exceptions.raise( exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED, {
|
|
55
|
+
details: "Multiple ServiceInstance initializations per process are not supported."
|
|
56
|
+
} );
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Ensure uniform 'ti-' prefix even if env is missing or custom starter script is used:
|
|
60
|
+
const envID = process.env.TI_INSTANCE_ID;
|
|
61
|
+
ServiceInstance.#instanceID = ( envID && String( envID ).startsWith( "ti-" ) ) ? envID : ( "ti-" + ( envID || tools.getUUID() ) );
|
|
62
|
+
|
|
52
63
|
ServiceInstance.#serviceDomainName = serviceDomainName;
|
|
53
64
|
this.#serviceConfig = ( _.isObjectLike( serviceConfig ) ) ? serviceConfig : { services: [] };
|
|
54
65
|
}
|
|
@@ -62,7 +73,9 @@ class ServiceInstance {
|
|
|
62
73
|
* @returns {string}
|
|
63
74
|
* @public
|
|
64
75
|
*/
|
|
65
|
-
static get instanceID() {
|
|
76
|
+
static get instanceID() {
|
|
77
|
+
return ServiceInstance.#instanceID;
|
|
78
|
+
}
|
|
66
79
|
|
|
67
80
|
/**
|
|
68
81
|
* Property returning the current service domain name.
|
|
@@ -71,7 +84,9 @@ class ServiceInstance {
|
|
|
71
84
|
* @returns {string}
|
|
72
85
|
* @public
|
|
73
86
|
*/
|
|
74
|
-
static get serviceDomainName() {
|
|
87
|
+
static get serviceDomainName() {
|
|
88
|
+
return ServiceInstance.#serviceDomainName;
|
|
89
|
+
}
|
|
75
90
|
|
|
76
91
|
/**
|
|
77
92
|
* Property to indicate that this and every child class is a {@link ServiceInstance}.
|
|
@@ -80,7 +95,9 @@ class ServiceInstance {
|
|
|
80
95
|
* @returns {boolean}
|
|
81
96
|
* @public
|
|
82
97
|
*/
|
|
83
|
-
get isServiceInstance() {
|
|
98
|
+
get isServiceInstance() {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
84
101
|
|
|
85
102
|
/**
|
|
86
103
|
* Property returning the service configuration JSON.
|
|
@@ -89,7 +106,9 @@ class ServiceInstance {
|
|
|
89
106
|
* @returns {ServiceConfiguration}
|
|
90
107
|
* @public
|
|
91
108
|
*/
|
|
92
|
-
get serviceConfig() {
|
|
109
|
+
get serviceConfig() {
|
|
110
|
+
return this.#serviceConfig;
|
|
111
|
+
}
|
|
93
112
|
|
|
94
113
|
/**
|
|
95
114
|
* Initializes the instance.
|
|
@@ -137,8 +156,7 @@ class ServiceInstance {
|
|
|
137
156
|
|
|
138
157
|
let configureInbound = ( this instanceof ServiceProvider );
|
|
139
158
|
let configureOutbound = ( this instanceof ServiceConsumer );
|
|
140
|
-
|
|
141
|
-
messageDispatcher.initialize( new DefaultMessageExchange( ServiceInstance.instanceID, ServiceInstance.serviceDomainName ), configureInbound, configureOutbound ).then( () => {
|
|
159
|
+
messageDispatcher.instance.initialize( new DefaultMessageExchange( ServiceInstance.instanceID, ServiceInstance.serviceDomainName ), configureInbound, configureOutbound ).then( () => {
|
|
142
160
|
resolve();
|
|
143
161
|
} ).catch( ( error ) => {
|
|
144
162
|
reject( exceptions.raise( error ) );
|
|
@@ -157,6 +175,8 @@ class ServiceInstance {
|
|
|
157
175
|
return new Promise( ( resolve, reject ) => {
|
|
158
176
|
this.#preStop().then( () => {
|
|
159
177
|
return this.onStop();
|
|
178
|
+
} ).then( () => {
|
|
179
|
+
return cache.instance.shutDown();
|
|
160
180
|
} ).then( () => {
|
|
161
181
|
return this.#postStop();
|
|
162
182
|
} ).then( () => {
|
|
@@ -172,7 +192,7 @@ class ServiceInstance {
|
|
|
172
192
|
* <br/>
|
|
173
193
|
* NOTE: This method will be invoked automatically.
|
|
174
194
|
* <br/>
|
|
175
|
-
* NOTE: If you need to add more onStop logic you can override this method but make sure to call it in the
|
|
195
|
+
* NOTE: If you need to add more onStop logic, you can override this method but make sure to call it in the
|
|
176
196
|
* overriding method using: super.onStop()
|
|
177
197
|
*
|
|
178
198
|
* @method
|
|
@@ -182,7 +202,7 @@ class ServiceInstance {
|
|
|
182
202
|
*/
|
|
183
203
|
onStop() {
|
|
184
204
|
return new Promise( ( resolve, reject ) => {
|
|
185
|
-
messageDispatcher.shutDown().then( () => {
|
|
205
|
+
messageDispatcher.instance.shutDown().then( () => {
|
|
186
206
|
resolve();
|
|
187
207
|
} ).catch( ( error ) => {
|
|
188
208
|
reject( exceptions.raise( error ) );
|
|
@@ -202,9 +222,9 @@ class ServiceInstance {
|
|
|
202
222
|
* @public
|
|
203
223
|
*/
|
|
204
224
|
reportHealthy() {
|
|
205
|
-
if ( cache.isOperational ) {
|
|
225
|
+
if ( cache.instance.isOperational ) {
|
|
206
226
|
let timestamp = new Date();
|
|
207
|
-
cache.setValue( this.#serviceHealthCheck, timestamp.toISOString(), config.getSetting( config.setting.SERVICE_HEALTH_CHECK_TIMEOUT ) ).catch( ( error ) => {
|
|
227
|
+
cache.instance.setValue( this.#serviceHealthCheck, timestamp.toISOString(), config.getSetting( config.setting.SERVICE_HEALTH_CHECK_TIMEOUT ) ).catch( ( error ) => {
|
|
208
228
|
logger.log( `Error while trying to report for health check from '${ ServiceInstance.instanceID }'!`, logger.logSeverity.WARNING, error );
|
|
209
229
|
} );
|
|
210
230
|
}
|
|
@@ -222,8 +242,8 @@ class ServiceInstance {
|
|
|
222
242
|
* @private
|
|
223
243
|
*/
|
|
224
244
|
#preStart() {
|
|
225
|
-
return new Promise( ( resolve
|
|
226
|
-
this.#serviceHealthCheck = config.getSetting( config.setting.SERVICE_HEALTH_CHECK_ADDRESS ) +
|
|
245
|
+
return new Promise( ( resolve ) => {
|
|
246
|
+
this.#serviceHealthCheck = config.getSetting( config.setting.SERVICE_HEALTH_CHECK_ADDRESS ) + ServiceInstance.serviceDomainName + ":" + ServiceInstance.instanceID;
|
|
227
247
|
resolve();
|
|
228
248
|
} );
|
|
229
249
|
}
|
|
@@ -238,8 +258,8 @@ class ServiceInstance {
|
|
|
238
258
|
* @private
|
|
239
259
|
*/
|
|
240
260
|
#postStart() {
|
|
241
|
-
return new Promise( ( resolve
|
|
242
|
-
//
|
|
261
|
+
return new Promise( ( resolve ) => {
|
|
262
|
+
// Schedule regular health check:
|
|
243
263
|
this.#reportHealthyJob = schedule.scheduleJob( config.getSetting( config.setting.SERVICE_HEALTH_CHECK_INTERVAL ), () => {
|
|
244
264
|
this.reportHealthy();
|
|
245
265
|
} );
|
|
@@ -263,11 +283,10 @@ class ServiceInstance {
|
|
|
263
283
|
* @private
|
|
264
284
|
*/
|
|
265
285
|
#preStop() {
|
|
266
|
-
return new Promise( ( resolve
|
|
286
|
+
return new Promise( ( resolve ) => {
|
|
267
287
|
if ( this.#reportHealthyJob ) {
|
|
268
288
|
this.#reportHealthyJob.cancel();
|
|
269
289
|
}
|
|
270
|
-
|
|
271
290
|
resolve();
|
|
272
291
|
} );
|
|
273
292
|
}
|
|
@@ -282,13 +301,12 @@ class ServiceInstance {
|
|
|
282
301
|
* @private
|
|
283
302
|
*/
|
|
284
303
|
#postStop() {
|
|
285
|
-
return new Promise( ( resolve
|
|
304
|
+
return new Promise( ( resolve ) => {
|
|
286
305
|
logger.log( `Instance '${ ServiceInstance.instanceID }' shut down successfully.`, logger.logSeverity.NOTICE );
|
|
287
|
-
|
|
288
306
|
resolve();
|
|
289
307
|
} );
|
|
290
308
|
}
|
|
291
309
|
|
|
292
310
|
}
|
|
293
311
|
|
|
294
|
-
module.exports = ServiceInstance;
|
|
312
|
+
module.exports = ServiceInstance;
|
|
@@ -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 ServiceConsumer = require( "#service-consumer" );
|
|
7
10
|
const _ = require( "lodash" );
|
|
@@ -71,7 +74,7 @@ class ServiceProvider extends ServiceConsumer {
|
|
|
71
74
|
let serviceDefinitions = this.serviceConfig.services;
|
|
72
75
|
return this.registerServices( serviceDefinitions );
|
|
73
76
|
} ).then( () => {
|
|
74
|
-
messageDispatcher.addMessageObserverRequestsIn( this.#serviceExecutor );
|
|
77
|
+
messageDispatcher.instance.addMessageObserverRequestsIn( this.#serviceExecutor );
|
|
75
78
|
resolve();
|
|
76
79
|
} ).catch( ( error ) => {
|
|
77
80
|
reject( exceptions.raise( error ) );
|
|
@@ -102,6 +105,22 @@ class ServiceProvider extends ServiceConsumer {
|
|
|
102
105
|
} );
|
|
103
106
|
}
|
|
104
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Used to report health status of the service instance for external monitoring.
|
|
110
|
+
* This is a scheduled job that will be executed at SERVICE_HEALTH_CHECK_INTERVAL time.
|
|
111
|
+
* <br/>
|
|
112
|
+
* NOTE: By default this method will update a Redis key with an expiration timer. You can override this
|
|
113
|
+
* functionality with something custom like calling an HTTP endpoint.
|
|
114
|
+
*
|
|
115
|
+
* @method
|
|
116
|
+
* @override
|
|
117
|
+
* @virtual
|
|
118
|
+
* @public
|
|
119
|
+
*/
|
|
120
|
+
reportHealthy() {
|
|
121
|
+
super.reportHealthy();
|
|
122
|
+
}
|
|
123
|
+
|
|
105
124
|
/**
|
|
106
125
|
* Used to verify whether the service caller has authorization to access the service.
|
|
107
126
|
* <br/>
|
|
@@ -184,10 +203,10 @@ class ServiceProvider extends ServiceConsumer {
|
|
|
184
203
|
// If this happens, a corresponding log entry will be created but the loading process will continue. Therefore, the following
|
|
185
204
|
// promise will always resolve (unless a programming error occurs in it of course).
|
|
186
205
|
let registrationPromise = ( serviceDefinition, defaultServiceHandler ) => {
|
|
187
|
-
return new Promise( ( resolve
|
|
206
|
+
return new Promise( ( resolve ) => {
|
|
188
207
|
this.registerService( serviceDefinition, defaultServiceHandler ).then( () => {
|
|
189
208
|
resolve( true );
|
|
190
|
-
} ).catch( (
|
|
209
|
+
} ).catch( () => {
|
|
191
210
|
resolve( false );
|
|
192
211
|
} );
|
|
193
212
|
} );
|
|
@@ -225,4 +244,4 @@ class ServiceProvider extends ServiceConsumer {
|
|
|
225
244
|
|
|
226
245
|
}
|
|
227
246
|
|
|
228
|
-
module.exports = ServiceProvider;
|
|
247
|
+
module.exports = ServiceProvider;
|
|
@@ -1,9 +1,13 @@
|
|
|
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 config = require( "#config" );
|
|
10
|
+
const tools = require( "#tools" );
|
|
7
11
|
|
|
8
12
|
/**
|
|
9
13
|
* Used to verify if the GCloud integration is enabled.
|
|
@@ -13,7 +17,7 @@ const config = require( "#config" );
|
|
|
13
17
|
* @public
|
|
14
18
|
*/
|
|
15
19
|
module.exports.isEnabled = () => {
|
|
16
|
-
return process.env.TI_GCLOUD_ENABLED
|
|
20
|
+
return tools.toBool( process.env.TI_GCLOUD_ENABLED );
|
|
17
21
|
};
|
|
18
22
|
|
|
19
23
|
/**
|