@ti-engine/core 1.6.1 → 1.7.2

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.
Files changed (33) hide show
  1. package/CHANGELOG.md +383 -364
  2. package/LICENSE.md +321 -321
  3. package/README.md +597 -548
  4. package/bin/localization/labels.json +122 -122
  5. package/bin/settings.json +41 -41
  6. package/bin/start-instance.js +164 -156
  7. package/components/auditing.js +191 -191
  8. package/components/connection-observer.js +72 -72
  9. package/components/definitions.types.js +248 -248
  10. package/components/exchange/default/default-message-exchange.js +136 -136
  11. package/components/exchange/default/default-message-receiver.js +101 -101
  12. package/components/exchange/default/default-message-sender.js +100 -100
  13. package/components/exchange/message-dispatcher.js +168 -168
  14. package/components/exchange/message-exchange.js +449 -449
  15. package/components/exchange/message-handler.js +235 -234
  16. package/components/exchange/message-memory-cache.js +190 -190
  17. package/components/exchange/message-observer.js +126 -126
  18. package/components/exchange/message-receiver.js +181 -181
  19. package/components/exchange/message-sender.js +143 -143
  20. package/components/exchange/message-tracer.js +212 -212
  21. package/components/service-caller.js +370 -370
  22. package/components/service-consumer.js +131 -131
  23. package/components/service-executor.js +278 -278
  24. package/components/service-instance.js +316 -316
  25. package/components/service-provider.js +251 -251
  26. package/integrations/redis-integration.js +591 -591
  27. package/package.json +89 -90
  28. package/utils/cache.js +772 -772
  29. package/utils/config.js +103 -103
  30. package/utils/exceptions.js +368 -368
  31. package/utils/localization.js +298 -298
  32. package/utils/logger.js +82 -82
  33. package/utils/tools.js +632 -632
@@ -1,317 +1,317 @@
1
- /*
2
- * The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.
3
- * Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
4
- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
5
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6
- * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
7
- */
8
-
9
- const _ = require( "lodash" );
10
- const schedule = require( "node-schedule" );
11
- const tools = require( "#tools" );
12
- const config = require( "#config" );
13
- const logger = require( "#logger" );
14
- const exceptions = require( "#exceptions" );
15
- const cache = require( "#cache" );
16
- const messageDispatcher = require( "#message-dispatcher" );
17
-
18
- /**
19
- * Abstract class used to define a Service Instance behavior.
20
- * <br/>
21
- * NOTE: Inherit this to create a module that can be started as a microservice instance.
22
- *
23
- * @class ServiceInstance
24
- * @abstract
25
- * @public
26
- */
27
- class ServiceInstance {
28
-
29
- static #instanceID;
30
- static #serviceDomainName;
31
- /** @type ServiceConfiguration */
32
- #serviceConfig;
33
- #serviceHealthCheck;
34
- #reportHealthyJob;
35
- #healthReportUnderway = false;
36
-
37
- /**
38
- * @constructor
39
- * @param {string} serviceDomainName The service domain name for this service instance.
40
- * @param {ServiceConfiguration} [serviceConfig={ services: [] }] The JSON configuration for this service.
41
- * @throws {TiException.E_GEN_ABSTRACT_CLASS_INIT} If this class is instantiated directly.
42
- * @throws {TiException.E_GEN_FEATURE_UNSUPPORTED} If multiple instances are started in the same process.
43
- */
44
- constructor( serviceDomainName, serviceConfig = { services: [] } ) {
45
- // Ensure this abstract class cannot be instantiated:
46
- if ( new.target === ServiceInstance ) {
47
- throw exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_CLASS_INIT, { name: this.constructor.name } );
48
- }
49
-
50
- // Guard against multiple instances in a single process (not supported):
51
- if ( ServiceInstance.#instanceID && ServiceInstance.#serviceDomainName ) {
52
- throw exceptions.raise( exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED, {
53
- details: "Multiple ServiceInstance initializations per process are not supported."
54
- } );
55
- }
56
-
57
- // Ensure a uniform 'ti-' prefix even if env is missing or a custom starter script is used:
58
- const envID = process.env.TI_INSTANCE_ID;
59
- ServiceInstance.#instanceID = ( envID && String( envID ).startsWith( "ti-" ) ) ? envID : ( "ti-" + ( envID || tools.getUUID() ) );
60
-
61
- ServiceInstance.#serviceDomainName = serviceDomainName;
62
- this.#serviceConfig = ( _.isObjectLike( serviceConfig ) ) ? serviceConfig : { services: [] };
63
- }
64
-
65
- /* Public interface */
66
-
67
- /**
68
- * Property returning the current service instance ID.
69
- *
70
- * @property
71
- * @returns {string}
72
- * @public
73
- */
74
- static get instanceID() {
75
- return ServiceInstance.#instanceID;
76
- }
77
-
78
- /**
79
- * Property returning the current service domain name.
80
- *
81
- * @property
82
- * @returns {string}
83
- * @public
84
- */
85
- static get serviceDomainName() {
86
- return ServiceInstance.#serviceDomainName;
87
- }
88
-
89
- /**
90
- * Property to indicate that this and every child class is a {@link ServiceInstance}.
91
- *
92
- * @property
93
- * @returns {boolean}
94
- * @public
95
- */
96
- get isServiceInstance() {
97
- return true;
98
- }
99
-
100
- /**
101
- * Property returning the service configuration JSON.
102
- *
103
- * @property
104
- * @returns {ServiceConfiguration}
105
- * @public
106
- */
107
- get serviceConfig() {
108
- return this.#serviceConfig;
109
- }
110
-
111
- /**
112
- * Initializes the instance.
113
- *
114
- * @method
115
- * @returns {Promise}
116
- * @public
117
- */
118
- start() {
119
- return new Promise( ( resolve, reject ) => {
120
- if ( !ServiceInstance.#serviceDomainName ) {
121
- reject( exceptions.raise( exceptions.exceptionCode.E_GEN_INVALID_SERVICE_DOMAIN_NAME ) );
122
- } else {
123
- this.#preStart().then( () => {
124
- return this.onStart();
125
- } ).then( () => {
126
- return this.#postStart();
127
- } ).then( () => {
128
- resolve();
129
- } ).catch( ( error ) => {
130
- reject( exceptions.raise( error ) );
131
- } );
132
- }
133
- } );
134
- }
135
-
136
- /**
137
- * Executes custom logic on instance start.
138
- * <br/>
139
- * NOTE: This method will be invoked automatically.
140
- * <br/>
141
- * NOTE: If you need to add more onStart logic, you can override this method but make sure to call it in the
142
- * overriding method using: super.onStart()
143
- *
144
- * @method
145
- * @returns {Promise}
146
- * @virtual
147
- * @public
148
- */
149
- onStart() {
150
- return new Promise( ( resolve, reject ) => {
151
- cache.instance.initialize().then( () => {
152
- const DefaultMessageExchange = require( "#default-message-exchange" );
153
- const ServiceProvider = require( "#service-provider" );
154
- const ServiceConsumer = require( "#service-consumer" );
155
-
156
- let configureInbound = ( this instanceof ServiceProvider );
157
- let configureOutbound = ( this instanceof ServiceConsumer );
158
-
159
- return messageDispatcher.instance.initialize( new DefaultMessageExchange( ServiceInstance.instanceID, ServiceInstance.serviceDomainName ), configureInbound, configureOutbound );
160
- } ).then( () => {
161
- resolve();
162
- } ).catch( ( error ) => {
163
- reject( exceptions.raise( error ) );
164
- } );
165
- } );
166
- }
167
-
168
- /**
169
- * Shuts down the instance.
170
- *
171
- * @method
172
- * @returns {Promise}
173
- * @public
174
- */
175
- stop() {
176
- return new Promise( ( resolve, reject ) => {
177
- this.#preStop().then( () => {
178
- return this.onStop();
179
- } ).then( () => {
180
- return cache.instance.shutDown();
181
- } ).then( () => {
182
- return this.#postStop();
183
- } ).then( () => {
184
- resolve();
185
- } ).catch( ( error ) => {
186
- reject( exceptions.raise( error ) );
187
- } );
188
- } );
189
- }
190
-
191
- /**
192
- * Executes custom logic on instance stop.
193
- * <br/>
194
- * NOTE: This method will be invoked automatically.
195
- * <br/>
196
- * NOTE: If you need to add more onStop logic, you can override this method but make sure to call it in the
197
- * overriding method using: super.onStop()
198
- *
199
- * @method
200
- * @returns {Promise}
201
- * @virtual
202
- * @public
203
- */
204
- onStop() {
205
- return new Promise( ( resolve, reject ) => {
206
- messageDispatcher.instance.shutDown().then( () => {
207
- resolve();
208
- } ).catch( ( error ) => {
209
- reject( exceptions.raise( error ) );
210
- } );
211
- } );
212
- }
213
-
214
- /**
215
- * Used to report health status of the service instance for external monitoring.
216
- * This is a scheduled job that will be executed at SERVICE_HEALTH_CHECK_INTERVAL time.
217
- * <br/>
218
- * NOTE: By default, this method will update a Redis key with an expiration timer. You can override this
219
- * functionality with something custom like calling an HTTP endpoint.
220
- *
221
- * @method
222
- * @virtual
223
- * @public
224
- */
225
- reportHealthy() {
226
- if ( cache.instance.isOperational && !this.#healthReportUnderway ) {
227
- this.#healthReportUnderway = true;
228
- let timestamp = new Date();
229
- cache.instance.setValue( this.#serviceHealthCheck, timestamp.toISOString(), config.getSetting( config.setting.SERVICE_HEALTH_CHECK_TIMEOUT ) ).then( () => {
230
- this.#healthReportUnderway = false;
231
- } ).catch( ( error ) => {
232
- this.#healthReportUnderway = false;
233
- logger.log( `Failed to report for health check from instance '${ ServiceInstance.instanceID }'!`, logger.logSeverity.WARNING, error );
234
- } );
235
- }
236
- }
237
-
238
- /* Private interface */
239
-
240
- /**
241
- * Used to run internal pre-start logic.
242
- * <br/>
243
- * NOTE: This will be executed before any user's custom logic in {@link ServiceInstance.onStart}.
244
- *
245
- * @method
246
- * @returns {Promise}
247
- * @private
248
- */
249
- #preStart() {
250
- return new Promise( ( resolve ) => {
251
- this.#serviceHealthCheck = config.getSetting( config.setting.SERVICE_HEALTH_CHECK_ADDRESS ) + ServiceInstance.serviceDomainName + ":" + ServiceInstance.instanceID;
252
- resolve();
253
- } );
254
- }
255
-
256
- /**
257
- * Used to run internal post-start logic.
258
- * <br/>
259
- * NOTE: This will be executed only after the user's custom logic in {@link ServiceInstance.onStart} has been successfully executed.
260
- *
261
- * @method
262
- * @returns {Promise}
263
- * @private
264
- */
265
- #postStart() {
266
- return new Promise( ( resolve ) => {
267
- // Schedule regular health check:
268
- this.#reportHealthyJob = schedule.scheduleJob( config.getSetting( config.setting.SERVICE_HEALTH_CHECK_INTERVAL ), () => {
269
- this.reportHealthy();
270
- } );
271
-
272
- logger.log( `Instance '${ ServiceInstance.instanceID }' started successfully.`, logger.logSeverity.NOTICE, {
273
- nodeVersion: process.version,
274
- operationMode: config.getSetting( config.setting.OPERATION_MODE )
275
- } );
276
-
277
- resolve();
278
- } );
279
- }
280
-
281
- /**
282
- * Used to run internal pre-start logic.
283
- * <br/>
284
- * NOTE: This will be executed before any user's custom logic in {@link ServiceInstance.onStop}.
285
- *
286
- * @method
287
- * @returns {Promise}
288
- * @private
289
- */
290
- #preStop() {
291
- return new Promise( ( resolve ) => {
292
- if ( this.#reportHealthyJob ) {
293
- this.#reportHealthyJob.cancel();
294
- }
295
- resolve();
296
- } );
297
- }
298
-
299
- /**
300
- * Used to run internal post-stop logic.
301
- * <br/>
302
- * NOTE: This will be executed only after the user's custom logic in {@link ServiceInstance.onStop} has been successfully executed.
303
- *
304
- * @method
305
- * @returns {Promise}
306
- * @private
307
- */
308
- #postStop() {
309
- return new Promise( ( resolve ) => {
310
- logger.log( `Instance '${ ServiceInstance.instanceID }' shut down successfully.`, logger.logSeverity.NOTICE );
311
- resolve();
312
- } );
313
- }
314
-
315
- }
316
-
1
+ /*
2
+ * The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.
3
+ * Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
5
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6
+ * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
7
+ */
8
+
9
+ const _ = require( "lodash" );
10
+ const schedule = require( "node-schedule" );
11
+ const tools = require( "#tools" );
12
+ const config = require( "#config" );
13
+ const logger = require( "#logger" );
14
+ const exceptions = require( "#exceptions" );
15
+ const cache = require( "#cache" );
16
+ const messageDispatcher = require( "#message-dispatcher" );
17
+
18
+ /**
19
+ * Abstract class used to define a Service Instance behavior.
20
+ * <br/>
21
+ * NOTE: Inherit this to create a module that can be started as a microservice instance.
22
+ *
23
+ * @class ServiceInstance
24
+ * @abstract
25
+ * @public
26
+ */
27
+ class ServiceInstance {
28
+
29
+ static #instanceID;
30
+ static #serviceDomainName;
31
+ /** @type ServiceConfiguration */
32
+ #serviceConfig;
33
+ #serviceHealthCheck;
34
+ #reportHealthyJob;
35
+ #healthReportUnderway = false;
36
+
37
+ /**
38
+ * @constructor
39
+ * @param {string} serviceDomainName The service domain name for this service instance.
40
+ * @param {ServiceConfiguration} [serviceConfig={ services: [] }] The JSON configuration for this service.
41
+ * @throws {TiException.E_GEN_ABSTRACT_CLASS_INIT} If this class is instantiated directly.
42
+ * @throws {TiException.E_GEN_FEATURE_UNSUPPORTED} If multiple instances are started in the same process.
43
+ */
44
+ constructor( serviceDomainName, serviceConfig = { services: [] } ) {
45
+ // Ensure this abstract class cannot be instantiated:
46
+ if ( new.target === ServiceInstance ) {
47
+ throw exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_CLASS_INIT, { name: this.constructor.name } );
48
+ }
49
+
50
+ // Guard against multiple instances in a single process (not supported):
51
+ if ( ServiceInstance.#instanceID && ServiceInstance.#serviceDomainName ) {
52
+ throw exceptions.raise( exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED, {
53
+ details: "Multiple ServiceInstance initializations per process are not supported."
54
+ } );
55
+ }
56
+
57
+ // Ensure a uniform 'ti-' prefix even if env is missing or a custom starter script is used:
58
+ const envID = process.env.TI_INSTANCE_ID;
59
+ ServiceInstance.#instanceID = ( envID && String( envID ).startsWith( "ti-" ) ) ? envID : ( "ti-" + ( envID || tools.getUUID() ) );
60
+
61
+ ServiceInstance.#serviceDomainName = serviceDomainName;
62
+ this.#serviceConfig = ( _.isObjectLike( serviceConfig ) ) ? serviceConfig : { services: [] };
63
+ }
64
+
65
+ /* Public interface */
66
+
67
+ /**
68
+ * Property returning the current service instance ID.
69
+ *
70
+ * @property
71
+ * @returns {string}
72
+ * @public
73
+ */
74
+ static get instanceID() {
75
+ return ServiceInstance.#instanceID;
76
+ }
77
+
78
+ /**
79
+ * Property returning the current service domain name.
80
+ *
81
+ * @property
82
+ * @returns {string}
83
+ * @public
84
+ */
85
+ static get serviceDomainName() {
86
+ return ServiceInstance.#serviceDomainName;
87
+ }
88
+
89
+ /**
90
+ * Property to indicate that this and every child class is a {@link ServiceInstance}.
91
+ *
92
+ * @property
93
+ * @returns {boolean}
94
+ * @public
95
+ */
96
+ get isServiceInstance() {
97
+ return true;
98
+ }
99
+
100
+ /**
101
+ * Property returning the service configuration JSON.
102
+ *
103
+ * @property
104
+ * @returns {ServiceConfiguration}
105
+ * @public
106
+ */
107
+ get serviceConfig() {
108
+ return this.#serviceConfig;
109
+ }
110
+
111
+ /**
112
+ * Initializes the instance.
113
+ *
114
+ * @method
115
+ * @returns {Promise}
116
+ * @public
117
+ */
118
+ start() {
119
+ return new Promise( ( resolve, reject ) => {
120
+ if ( !ServiceInstance.#serviceDomainName ) {
121
+ reject( exceptions.raise( exceptions.exceptionCode.E_GEN_INVALID_SERVICE_DOMAIN_NAME ) );
122
+ } else {
123
+ this.#preStart().then( () => {
124
+ return this.onStart();
125
+ } ).then( () => {
126
+ return this.#postStart();
127
+ } ).then( () => {
128
+ resolve();
129
+ } ).catch( ( error ) => {
130
+ reject( exceptions.raise( error ) );
131
+ } );
132
+ }
133
+ } );
134
+ }
135
+
136
+ /**
137
+ * Executes custom logic on instance start.
138
+ * <br/>
139
+ * NOTE: This method will be invoked automatically.
140
+ * <br/>
141
+ * NOTE: If you need to add more onStart logic, you can override this method but make sure to call it in the
142
+ * overriding method using: super.onStart()
143
+ *
144
+ * @method
145
+ * @returns {Promise}
146
+ * @virtual
147
+ * @public
148
+ */
149
+ onStart() {
150
+ return new Promise( ( resolve, reject ) => {
151
+ cache.instance.initialize().then( () => {
152
+ const DefaultMessageExchange = require( "#default-message-exchange" );
153
+ const ServiceProvider = require( "#service-provider" );
154
+ const ServiceConsumer = require( "#service-consumer" );
155
+
156
+ let configureInbound = ( this instanceof ServiceProvider );
157
+ let configureOutbound = ( this instanceof ServiceConsumer );
158
+
159
+ return messageDispatcher.instance.initialize( new DefaultMessageExchange( ServiceInstance.instanceID, ServiceInstance.serviceDomainName ), configureInbound, configureOutbound );
160
+ } ).then( () => {
161
+ resolve();
162
+ } ).catch( ( error ) => {
163
+ reject( exceptions.raise( error ) );
164
+ } );
165
+ } );
166
+ }
167
+
168
+ /**
169
+ * Shuts down the instance.
170
+ *
171
+ * @method
172
+ * @returns {Promise}
173
+ * @public
174
+ */
175
+ stop() {
176
+ return new Promise( ( resolve, reject ) => {
177
+ this.#preStop().then( () => {
178
+ return this.onStop();
179
+ } ).then( () => {
180
+ return cache.instance.shutDown();
181
+ } ).then( () => {
182
+ return this.#postStop();
183
+ } ).then( () => {
184
+ resolve();
185
+ } ).catch( ( error ) => {
186
+ reject( exceptions.raise( error ) );
187
+ } );
188
+ } );
189
+ }
190
+
191
+ /**
192
+ * Executes custom logic on instance stop.
193
+ * <br/>
194
+ * NOTE: This method will be invoked automatically.
195
+ * <br/>
196
+ * NOTE: If you need to add more onStop logic, you can override this method but make sure to call it in the
197
+ * overriding method using: super.onStop()
198
+ *
199
+ * @method
200
+ * @returns {Promise}
201
+ * @virtual
202
+ * @public
203
+ */
204
+ onStop() {
205
+ return new Promise( ( resolve, reject ) => {
206
+ messageDispatcher.instance.shutDown().then( () => {
207
+ resolve();
208
+ } ).catch( ( error ) => {
209
+ reject( exceptions.raise( error ) );
210
+ } );
211
+ } );
212
+ }
213
+
214
+ /**
215
+ * Used to report health status of the service instance for external monitoring.
216
+ * This is a scheduled job that will be executed at SERVICE_HEALTH_CHECK_INTERVAL time.
217
+ * <br/>
218
+ * NOTE: By default, this method will update a Redis key with an expiration timer. You can override this
219
+ * functionality with something custom like calling an HTTP endpoint.
220
+ *
221
+ * @method
222
+ * @virtual
223
+ * @public
224
+ */
225
+ reportHealthy() {
226
+ if ( cache.instance.isOperational && !this.#healthReportUnderway ) {
227
+ this.#healthReportUnderway = true;
228
+ let timestamp = new Date();
229
+ cache.instance.setValue( this.#serviceHealthCheck, timestamp.toISOString(), config.getSetting( config.setting.SERVICE_HEALTH_CHECK_TIMEOUT ) ).then( () => {
230
+ this.#healthReportUnderway = false;
231
+ } ).catch( ( error ) => {
232
+ this.#healthReportUnderway = false;
233
+ logger.log( `Failed to report for health check from instance '${ ServiceInstance.instanceID }'!`, logger.logSeverity.WARNING, error );
234
+ } );
235
+ }
236
+ }
237
+
238
+ /* Private interface */
239
+
240
+ /**
241
+ * Used to run internal pre-start logic.
242
+ * <br/>
243
+ * NOTE: This will be executed before any user's custom logic in {@link ServiceInstance.onStart}.
244
+ *
245
+ * @method
246
+ * @returns {Promise}
247
+ * @private
248
+ */
249
+ #preStart() {
250
+ return new Promise( ( resolve ) => {
251
+ this.#serviceHealthCheck = config.getSetting( config.setting.SERVICE_HEALTH_CHECK_ADDRESS ) + ServiceInstance.serviceDomainName + ":" + ServiceInstance.instanceID;
252
+ resolve();
253
+ } );
254
+ }
255
+
256
+ /**
257
+ * Used to run internal post-start logic.
258
+ * <br/>
259
+ * NOTE: This will be executed only after the user's custom logic in {@link ServiceInstance.onStart} has been successfully executed.
260
+ *
261
+ * @method
262
+ * @returns {Promise}
263
+ * @private
264
+ */
265
+ #postStart() {
266
+ return new Promise( ( resolve ) => {
267
+ // Schedule regular health check:
268
+ this.#reportHealthyJob = schedule.scheduleJob( config.getSetting( config.setting.SERVICE_HEALTH_CHECK_INTERVAL ), () => {
269
+ this.reportHealthy();
270
+ } );
271
+
272
+ logger.log( `Instance '${ ServiceInstance.instanceID }' started successfully.`, logger.logSeverity.NOTICE, {
273
+ nodeVersion: process.version,
274
+ operationMode: config.getSetting( config.setting.OPERATION_MODE )
275
+ } );
276
+
277
+ resolve();
278
+ } );
279
+ }
280
+
281
+ /**
282
+ * Used to run internal pre-start logic.
283
+ * <br/>
284
+ * NOTE: This will be executed before any user's custom logic in {@link ServiceInstance.onStop}.
285
+ *
286
+ * @method
287
+ * @returns {Promise}
288
+ * @private
289
+ */
290
+ #preStop() {
291
+ return new Promise( ( resolve ) => {
292
+ if ( this.#reportHealthyJob ) {
293
+ this.#reportHealthyJob.cancel();
294
+ }
295
+ resolve();
296
+ } );
297
+ }
298
+
299
+ /**
300
+ * Used to run internal post-stop logic.
301
+ * <br/>
302
+ * NOTE: This will be executed only after the user's custom logic in {@link ServiceInstance.onStop} has been successfully executed.
303
+ *
304
+ * @method
305
+ * @returns {Promise}
306
+ * @private
307
+ */
308
+ #postStop() {
309
+ return new Promise( ( resolve ) => {
310
+ logger.log( `Instance '${ ServiceInstance.instanceID }' shut down successfully.`, logger.logSeverity.NOTICE );
311
+ resolve();
312
+ } );
313
+ }
314
+
315
+ }
316
+
317
317
  module.exports = ServiceInstance;