@nsshunt/stsappframework 3.0.104 → 3.0.106

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 (124) hide show
  1. package/dist/influxdb/influxDBManager.js +16 -17
  2. package/dist/influxdb/influxDBManager.js.map +1 -1
  3. package/dist/influxdb/influxDBManagerAgent.js +9 -13
  4. package/dist/influxdb/influxDBManagerAgent.js.map +1 -1
  5. package/dist/influxdb/influxDBManagerBase.js +2 -6
  6. package/dist/influxdb/influxDBManagerBase.js.map +1 -1
  7. package/dist/influxdb/influxDBManagerService.js +10 -14
  8. package/dist/influxdb/influxDBManagerService.js.map +1 -1
  9. package/dist/instrumentationsubscriber.js +11 -15
  10. package/dist/instrumentationsubscriber.js.map +1 -1
  11. package/dist/kafka/IMKafkaManager.js +2 -6
  12. package/dist/kafka/IMKafkaManager.js.map +1 -1
  13. package/dist/kafkatesting/produce.js +1 -5
  14. package/dist/kafkatesting/produce.js.map +1 -1
  15. package/dist/processbase.js +7 -8
  16. package/dist/processbase.js.map +1 -1
  17. package/dist/server.js +1 -1
  18. package/dist/server.js.map +1 -1
  19. package/dist/tcpclient/app2.js +2 -2
  20. package/dist/tcpserver/appmaster.js +39 -16
  21. package/dist/tcpserver/appmaster.js.map +1 -1
  22. package/package.json +7 -7
  23. package/src/influxdb/influxDBManager.ts +16 -18
  24. package/src/influxdb/influxDBManagerAgent.ts +9 -11
  25. package/src/influxdb/influxDBManagerBase.ts +2 -4
  26. package/src/influxdb/influxDBManagerService.ts +10 -12
  27. package/src/instrumentationsubscriber.ts +11 -14
  28. package/src/kafka/IMKafkaManager.ts +2 -4
  29. package/src/kafkatesting/produce.ts +1 -3
  30. package/src/processbase.ts +7 -9
  31. package/src/server.ts +1 -1
  32. package/src/tcpclient/app2.ts +2 -2
  33. package/src/tcpserver/appmaster.ts +39 -17
  34. package/types/influxdb/influxDBManager.d.ts.map +1 -1
  35. package/types/influxdb/influxDBManagerAgent.d.ts.map +1 -1
  36. package/types/influxdb/influxDBManagerBase.d.ts.map +1 -1
  37. package/types/influxdb/influxDBManagerService.d.ts.map +1 -1
  38. package/types/instrumentationsubscriber.d.ts.map +1 -1
  39. package/types/kafka/IMKafkaManager.d.ts.map +1 -1
  40. package/types/processbase.d.ts +2 -2
  41. package/types/processbase.d.ts.map +1 -1
  42. package/types/tcpserver/appmaster.d.ts.map +1 -1
  43. package/src_working/authDefs.ts +0 -37
  44. package/src_working/authutilsnode.ts +0 -373
  45. package/src_working/commonTypes.ts +0 -239
  46. package/src_working/index.ts +0 -22
  47. package/src_working/influxdb/influxDBManager.ts +0 -970
  48. package/src_working/influxdb/influxDBManagerAgent.ts +0 -314
  49. package/src_working/influxdb/influxDBManagerBase.ts +0 -109
  50. package/src_working/influxdb/influxDBManagerService.ts +0 -373
  51. package/src_working/instrumentationsubscriber.ts +0 -283
  52. package/src_working/kafka/IMKafkaManager.ts +0 -152
  53. package/src_working/kafka/kafkaconsumer.ts +0 -82
  54. package/src_working/kafka/kafkamanager.ts +0 -186
  55. package/src_working/kafka/kafkaproducer.ts +0 -58
  56. package/src_working/kafkatesting/config.ts +0 -10
  57. package/src_working/kafkatesting/consume.ts +0 -116
  58. package/src_working/kafkatesting/produce.ts +0 -153
  59. package/src_working/masterprocessbase.ts +0 -598
  60. package/src_working/middleware/serverNetworkMiddleware.ts +0 -240
  61. package/src_working/network.ts +0 -36
  62. package/src_working/processbase.ts +0 -411
  63. package/src_working/processoptions.ts +0 -164
  64. package/src_working/publishertransports/publishTransportDirect.ts +0 -45
  65. package/src_working/publishertransports/publishTransportUtils.ts +0 -53
  66. package/src_working/server.ts +0 -141
  67. package/src_working/serverprocessbase.ts +0 -393
  68. package/src_working/singleprocessbase.ts +0 -121
  69. package/src_working/socketIoServerHelper.ts +0 -177
  70. package/src_working/stscontrollerbase.ts +0 -15
  71. package/src_working/stslatencycontroller.ts +0 -27
  72. package/src_working/stslatencyroute.ts +0 -16
  73. package/src_working/stsrouterbase.ts +0 -22
  74. package/src_working/tcpclient/app.ts +0 -19
  75. package/src_working/tcpclient/app2.ts +0 -56
  76. package/src_working/tcpserver/app.ts +0 -11
  77. package/src_working/tcpserver/appConfig.ts +0 -65
  78. package/src_working/tcpserver/appmaster.ts +0 -544
  79. package/src_working/validation/errors.ts +0 -6
  80. package/src_working/webworkertesting/app.ts +0 -49
  81. package/src_working/webworkertesting/worker.ts +0 -24
  82. package/src_working/workerprocessbase.test.ts +0 -47
  83. package/src_working/workerprocessbase.ts +0 -185
  84. package/src_working2/authDefs.ts +0 -37
  85. package/src_working2/authutilsnode.ts +0 -375
  86. package/src_working2/commonTypes.ts +0 -239
  87. package/src_working2/index.ts +0 -22
  88. package/src_working2/influxdb/influxDBManager.ts +0 -972
  89. package/src_working2/influxdb/influxDBManagerAgent.ts +0 -316
  90. package/src_working2/influxdb/influxDBManagerBase.ts +0 -111
  91. package/src_working2/influxdb/influxDBManagerService.ts +0 -375
  92. package/src_working2/instrumentationsubscriber.ts +0 -286
  93. package/src_working2/kafka/IMKafkaManager.ts +0 -154
  94. package/src_working2/kafka/kafkaconsumer.ts +0 -82
  95. package/src_working2/kafka/kafkamanager.ts +0 -186
  96. package/src_working2/kafka/kafkaproducer.ts +0 -58
  97. package/src_working2/kafkatesting/config.ts +0 -10
  98. package/src_working2/kafkatesting/consume.ts +0 -116
  99. package/src_working2/kafkatesting/produce.ts +0 -155
  100. package/src_working2/masterprocessbase.ts +0 -590
  101. package/src_working2/middleware/serverNetworkMiddleware.ts +0 -240
  102. package/src_working2/network.ts +0 -36
  103. package/src_working2/processbase.ts +0 -415
  104. package/src_working2/processoptions.ts +0 -164
  105. package/src_working2/publishertransports/publishTransportDirect.ts +0 -45
  106. package/src_working2/publishertransports/publishTransportUtils.ts +0 -53
  107. package/src_working2/server.ts +0 -141
  108. package/src_working2/serverprocessbase.ts +0 -393
  109. package/src_working2/singleprocessbase.ts +0 -123
  110. package/src_working2/socketIoServerHelper.ts +0 -177
  111. package/src_working2/stscontrollerbase.ts +0 -15
  112. package/src_working2/stslatencycontroller.ts +0 -27
  113. package/src_working2/stslatencyroute.ts +0 -16
  114. package/src_working2/stsrouterbase.ts +0 -22
  115. package/src_working2/tcpclient/app.ts +0 -19
  116. package/src_working2/tcpclient/app2.ts +0 -56
  117. package/src_working2/tcpserver/app.ts +0 -11
  118. package/src_working2/tcpserver/appConfig.ts +0 -65
  119. package/src_working2/tcpserver/appmaster.ts +0 -522
  120. package/src_working2/validation/errors.ts +0 -6
  121. package/src_working2/webworkertesting/app.ts +0 -49
  122. package/src_working2/webworkertesting/worker.ts +0 -24
  123. package/src_working2/workerprocessbase.test.ts +0 -47
  124. package/src_working2/workerprocessbase.ts +0 -187
@@ -1,598 +0,0 @@
1
- /* eslint @typescript-eslint/no-explicit-any: 0, @typescript-eslint/no-unused-vars: 0 */ // --> OFF
2
- import fs from "fs"
3
- import si from 'systeminformation' // https://systeminformation.io/
4
- import https from 'https'
5
-
6
- import axios from 'axios';
7
-
8
- import cluster, { Worker } from 'node:cluster'
9
-
10
- import os from 'os';
11
-
12
- import colors from 'colors'
13
-
14
- import express from 'express'
15
-
16
- import { setupPrimary } from '@socket.io/cluster-adapter'
17
- import { createServer as createServerHttps } from 'https'
18
- import { createServer } from 'http'
19
- import { AggregatorRegistry } from 'prom-client'
20
-
21
- import { $Options } from '@nsshunt/stsconfig'
22
- const goptions = $Options()
23
-
24
- import debugModule from 'debug'
25
-
26
- import { Gauge, GaugeTypes, InstrumentGaugeTelemetry, InstrumentGaugeOptions, InstrumentHistogramTelemetry } from '@nsshunt/stsinstrumentation'
27
- import { GetFirstNetworkInterface } from './network'
28
-
29
- import { ProcessOptions, STSServerType } from './processoptions'
30
- import { ProcessBase } from './processbase';
31
- import { IMasterProcessBase } from './commonTypes';
32
-
33
- import { InstrumentDefinitions } from '@nsshunt/stspublisherserver'
34
- import { IPCMessagePayload, IPCMessageCommand } from './commonTypes'
35
- import { REQUEST_HEADER_FIELDS_TOO_LARGE } from "http-status-codes";
36
-
37
-
38
- export class MasterProcessBase extends ProcessBase implements IMasterProcessBase
39
- {
40
- //static WORKER_MESSAGE_EVENT = 'sts_worker_message_event';
41
- #masterProcessExitTime = goptions.masterProcessExitTime;
42
- #childProcessExitTime = goptions.childProcessExitTime;
43
- #siValueObject = {
44
- currentLoad: 'currentLoad'
45
- }
46
- #httpServer: any = null; // Prometheus cluster server. See https://github.com/siimon/prom-client/blob/master/example/cluster.js
47
- #metricsServer: any= null;
48
- #aggregatorRegistry: any = null;
49
- #httpsAgent: any;
50
- #debug = debugModule(`proc:${process.pid}`);
51
- #checkLatency: NodeJS.Timeout | null = null;
52
- #killWorkers: Record<string, string> = { };
53
- #workers = 1; // Start at 1 becuase of main thread
54
- #shuttingDown = false;
55
-
56
- constructor(options: ProcessOptions)
57
- {
58
- super(options);
59
-
60
- this.#httpsAgent = new https.Agent({
61
- // Use basic defaults. This agent will not use keep-alive.
62
- timeout: goptions.timeout,
63
- rejectUnauthorized: goptions.isProduction // Allows self-signed certificates if non-production
64
- });
65
- }
66
-
67
- override CollectAdditionalTelemetry(): void {
68
- si.get(this.#siValueObject).then(data => {
69
- this.UpdateInstrument(Gauge.CPU_SYSTEM_LOAD_GAUGE, {
70
- val: data.currentLoad.currentLoad
71
- } as InstrumentGaugeTelemetry);
72
- });
73
- }
74
-
75
- override GetAdditionalInstruments(): InstrumentDefinitions {
76
- return [
77
- [ Gauge.CPU_SYSTEM_LOAD_GAUGE, GaugeTypes.INSTRUMENT_GAUGE, {
78
- interval: goptions.instrumentationObservationInterval,
79
- sampleSize: goptions.instrumentationTimeWindow
80
- } as InstrumentGaugeOptions]
81
- ]
82
- }
83
-
84
- /**
85
- * Note: msg removed from signature but will be passed at run-time.
86
- * @param {*} msg
87
- */
88
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
89
- WorkerMessageEvent(msg: any)
90
- {
91
- return null;
92
- }
93
-
94
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
95
- #WorkerMessageEvent(msg: any)
96
- {
97
- if (msg.command) {
98
- this.WorkerMessageEvent(msg);
99
- }
100
- }
101
-
102
- #InitCluster = (LogEx: any) =>
103
- {
104
- cluster.on('listening', () => {
105
- let allListening = true;
106
- for (const worker of Object.values(cluster.workers as NodeJS.Dict<Worker>)) {
107
- if (worker?.isConnected) {
108
- allListening = false;
109
- break;
110
- }
111
- }
112
-
113
- if (allListening) {
114
- LogEx(`Service instance started.`);
115
- }
116
- });
117
- };
118
-
119
- // https://github.com/siimon/prom-client/blob/master/example/cluster.js
120
- #SetupPrometheusForMaster = (LogEx: any) => {
121
- this.#metricsServer = express();
122
- this.#aggregatorRegistry = new AggregatorRegistry();
123
-
124
- switch (this.options.serverType) {
125
- case STSServerType.EXPRESS_TLS : {
126
- const options = {
127
- key: fs.readFileSync(this.options.httpsServerKeyPath),
128
- cert: fs.readFileSync(this.options.httpsServerCertificatePath)
129
- };
130
- this.#httpServer = createServerHttps(options, this.#metricsServer);
131
- }
132
- break;
133
- case STSServerType.EXPRESS : {
134
- this.#httpServer = createServer(this.#metricsServer);
135
- }
136
- }
137
- //this.#httpServer.maxConnections = 50;
138
-
139
- this.#metricsServer.get('/cluster_metrics', async (req: any, res: any) => {
140
- try {
141
- const metrics = await this.#aggregatorRegistry.clusterMetrics();
142
- res.set('Content-Type', this.#aggregatorRegistry.contentType);
143
- res.send(metrics);
144
- } catch (ex: any) {
145
- res.statusCode = 500;
146
- res.send(ex.message);
147
- }
148
- });
149
-
150
- //@@@ options wrong
151
-
152
- try {
153
- // https://stackoverflow.com/questions/21342828/node-express-unix-domain-socket-permissions
154
- //@@httpServer.listen('/tmp/stsrest01.sock').on('listening', () =>
155
- //@@httpServer.listen('/var/run/sts/stsrest01.sock').on('listening', () =>
156
- //@@httpServer.listen('/var/lib/sts/stsrest01.sock').on('listening', () =>
157
- this.#httpServer.listen(this.options.prometheusClusterPort, () => {
158
- //@@chmodSync(this.options.port, 511);
159
- }).on('listening', () =>
160
- {
161
- LogEx(`Prometheus scrapes ready and live on ${this.options.endpoint}:${this.options.prometheusClusterPort}/metrics`);
162
- });
163
- } catch (error)
164
- {
165
- console.error(error);
166
- throw error;
167
- }
168
- }
169
-
170
- #CheckLatency = async () => {
171
- const start = process.hrtime();
172
- await this.#GetLatency();
173
- this.#LatencyRequestCompleted(start);
174
- }
175
-
176
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
177
- #GetLatency = async (): Promise<any> => {
178
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
179
- let retVal: any = null;
180
- // We use port rather than hostport becuase this test going outside the service and comes back in as a regular client
181
- const url = `${this.options.endpoint}:${this.options.port}${this.options.apiRoot}/latency`;
182
- const headers = {
183
- 'Content-Type': 'application/json'
184
- };
185
- try {
186
- retVal = await axios({
187
- url: url
188
- ,method: 'get'
189
- ,headers: headers
190
- ,httpsAgent: this.#httpsAgent
191
- });
192
- if (retVal.status !== 200) {
193
- this.#debug(`Error (MasterProcessBase:#GetLatency): Invalid response from server: [${retVal.status}]`.magenta);
194
- return null;
195
- }
196
- return retVal.data.detail;
197
- } catch (error: any) {
198
- this.#debug(`Error (MasterProcessBase:#GetLatency:catch): [${error}]`.red);
199
- this.#debug(` url: [${url}]`.red);
200
- if (error.response && error.response.data) {
201
- this.#debug(` Details: [${JSON.stringify(error.response.data)}]`.red);
202
- }
203
- }
204
- }
205
-
206
- #LatencyRequestCompleted = (start: any) => {
207
- // Update request duration histo data
208
- let timeInMs = 0;
209
- const end = process.hrtime(start);
210
- timeInMs = (end[0]* 1000000000 + end[1]) / 1000000;
211
- timeInMs = parseFloat(timeInMs.toFixed(4));
212
-
213
- this.UpdateInstrument(Gauge.LATENCY_HISTOGRAM_GAUGE, {
214
- val: timeInMs
215
- } as InstrumentHistogramTelemetry);
216
-
217
- this.UpdateInstrument(Gauge.LATENCY_GAUGE, {
218
- val: timeInMs
219
- } as InstrumentGaugeTelemetry);
220
- };
221
-
222
- SetupServer = async () =>
223
- {
224
- this.SetupInstrumentation();
225
- setTimeout(() => {
226
- this.SetupServerEx();
227
- }, 100);
228
- }
229
-
230
- #_KillWorker = (id: string, signal: NodeJS.Signals, killProcess: boolean): boolean => {
231
- if (cluster.workers && cluster.workers[id]) {
232
- const worker = cluster.workers[id] as Worker;
233
- if (worker.process) {
234
- this.LogEx(`Sending terminate message `.grey + `(initiated by ${signal})`.yellow + ` for worker PID: ${worker.process.pid}`.grey);
235
- const command: string = (killProcess ? 'TerminateAndKill' : 'Terminate');
236
- worker.process.send( { command } );
237
- return true;
238
- } else {
239
- this.LogEx(`Could not kill worker with id: [${id}]. The process does not exists`.red);
240
- return false;
241
- }
242
- } else {
243
- this.LogEx(`Could not kill worker with id: [${id}]. Worker does not exist within workers collection`.red);
244
- return false;
245
- }
246
- }
247
-
248
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
249
- KillWorker = (id: string, signal: NodeJS.Signals = "SIGTERM", options: any, killProcess: boolean, allowKillAll: boolean): boolean => {
250
- if (allowKillAll || Object.keys(cluster.workers as NodeJS.Dict<Worker>).length > 1) {
251
- if (id.localeCompare('0') === 0) {
252
- const keys = Object.keys(cluster.workers as NodeJS.Dict<Worker>);
253
- for (let i=keys.length-1; i > 0; i--) {
254
- // Kill the last one added (assumed node keeps them in order)
255
- id = keys[i];
256
- if (!this.#killWorkers[id]) {
257
- this.#killWorkers[id] = id;
258
- // Allow some time for the worker to be terminated before clean-up of the killWorkers array
259
- setTimeout(() => {
260
- delete this.#killWorkers[id];
261
- }, 2000).unref(); //@@
262
- return this.#_KillWorker(id, signal, killProcess);
263
- }
264
- }
265
- return false;
266
- } else {
267
- return this.#_KillWorker(id, signal, killProcess);
268
- }
269
- } else {
270
- this.LogEx(`Not allowed to kill the last worker process.`.yellow);
271
- return false;
272
- }
273
- }
274
-
275
- KillWorkers = (signal: NodeJS.Signals): void => {
276
- try {
277
- for (const id in cluster.workers) {
278
- try {
279
- this.KillWorker(id, signal, null, false, true);
280
- //cluster.workers[id].process.kill(signal);
281
-
282
- // Using kill (below) does not fire the events in the worker processes.
283
- //cluster.workers[id].kill('SIGINT');
284
- } catch (error) {
285
- this.LogEx(error);
286
- }
287
- }
288
- } catch (error) {
289
- this.LogEx(error);
290
- }
291
- }
292
-
293
- #UpdateWorkersInstrument = (): void => {
294
- setTimeout(() => {
295
- this.UpdateInstrument(Gauge.CORE_COUNT_GAUGE, {
296
- val: this.#workers
297
- } as InstrumentGaugeTelemetry);
298
- }, 2000);
299
- }
300
-
301
- IncWorkers = (): void => {
302
- this.#workers++;
303
- this.#debug(` Inc Workers. Total thread count: [${this.#workers}]`);
304
- this.#UpdateWorkersInstrument();
305
- }
306
-
307
- DecWorkers = (): void => {
308
- this.#workers--;
309
- this.#debug(` Dec Workers. Total thread count: [${this.#workers}]`);
310
- this.#UpdateWorkersInstrument();
311
- }
312
-
313
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
314
- AddWorker = (options: any): number => {
315
- const workerId: number = this.#SpawnWorker(options);
316
- this.#debug(` Spawned worker with id: [${workerId}]`.yellow);
317
- if (options) {
318
- this.#debug(` Options: [${JSON.stringify(options)}]`.yellow);
319
- }
320
- return workerId;
321
- }
322
-
323
- #processIPCCommand = async (iPCMessagePayload: IPCMessagePayload): Promise<IPCMessagePayload> => {
324
- this.#debug(` Processing message command: [${iPCMessagePayload.command}]`.yellow);
325
- switch (iPCMessagePayload.command) {
326
- case IPCMessageCommand.AddWorker : {
327
- const workerId = this.AddWorker(iPCMessagePayload.requestDetail?.options);
328
- iPCMessagePayload.responseDetail = {
329
- workerId
330
- }
331
- return iPCMessagePayload;
332
- }
333
- case IPCMessageCommand.DeleteWorker : {
334
- const workerId = iPCMessagePayload.requestDetail?.workerId;
335
- const workerKilled = this.KillWorker(workerId, "SIGTERM", iPCMessagePayload.requestDetail?.options, true, false);
336
- this.#debug(` Killed worker with id: [${workerId}]`.yellow);
337
- iPCMessagePayload.responseDetail = {
338
- workerId,
339
- workerKilled
340
- }
341
- return iPCMessagePayload;
342
- }
343
- default : {
344
- const errorMessage = `Could not process command: [${iPCMessagePayload.command}].`;
345
- this.#debug(` ${errorMessage}`.red);
346
- throw new Error(errorMessage);
347
- }
348
- }
349
- }
350
-
351
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
352
- #SpawnWorker = (spawnWorkerOptions?: any): number => {
353
- const workerEnv: any = { };
354
- workerEnv['STS_GSD_SII'] = JSON.stringify(this.options);
355
- if (spawnWorkerOptions) {
356
- workerEnv['STS_GSD_OPTIONS'] = JSON.stringify(spawnWorkerOptions);
357
- }
358
-
359
- // https://nodejs.org/api/cluster.html#clustersetupprimarysettings
360
- if (this.options.workerExec) {
361
- cluster.setupPrimary({
362
- exec: this.options.workerExec,
363
- silent: true,
364
- });
365
- }
366
-
367
- const worker = cluster.fork(workerEnv);
368
- this.IncWorkers();
369
-
370
- worker.on('exit', (code, signal) => {
371
- if (signal) {
372
- this.LogEx(`Worker: ${worker.process.pid} was killed by signal: ${signal}`);
373
- } else if (code !== 0) {
374
- this.LogEx(`Worker: ${worker.process.pid} exited with error code: ${code}`);
375
- } else {
376
- this.LogEx(`Worker: ${worker.process.pid} exited successfully, code: ${code}, signal: ${signal}`);
377
- }
378
- });
379
-
380
- worker.on('message', async (payload) => {
381
- // Only handle request/response message types here ...
382
- if (payload.requestResponse) {
383
- const iPCMessagePayload: IPCMessagePayload = payload as IPCMessagePayload;
384
- this.#debug(`Received message with id: [${iPCMessagePayload.id}] from worker: [${worker.process.pid}]. Details: [${JSON.stringify(iPCMessagePayload)}]`.yellow);
385
- const response: IPCMessagePayload = await this.#processIPCCommand(iPCMessagePayload);
386
- this.#debug(`Sending response message with id: [${iPCMessagePayload.id}] to worker: [${worker.process.pid}]. Details: [${JSON.stringify(response)}]`.green);
387
- worker.send(response);
388
- } else {
389
- this.#WorkerMessageEvent(payload);
390
- }
391
- });
392
-
393
- return worker.id;
394
- };
395
-
396
- MasterStarted(): void { // eslint-disable @typescript-eslint/no-empty-function
397
-
398
- }
399
-
400
- override get shuttingDown(): boolean {
401
- return this.#shuttingDown;
402
- }
403
-
404
- ProcessTerminating = async (): Promise<void> => {
405
- return;
406
- }
407
-
408
- SetupServerEx = async () =>
409
- {
410
- this.ProcessStartup();
411
- const LogEx = this.LogEx;
412
-
413
- LogEx(`Service instance starting. Instance Id: [${this.options.serviceInstanceId}]`);
414
-
415
- this.LogSystemTelemetry();
416
-
417
- // socket.io
418
- // setup connections between the workers
419
- if (this.options.wssServer === true) {
420
- if (this.options.useRedisAdaptor) {
421
- LogEx(`Using Redis for socket.io cluster management (master)`);
422
- } else {
423
- LogEx(`Using nodejs cluster mode for socket.io cluster management`);
424
- setupPrimary();
425
- }
426
- }
427
-
428
- if (this.options.prometheusSupport === true) {
429
- this.#SetupPrometheusForMaster(LogEx);
430
- }
431
-
432
- const numCPUs = await this.GetNumCPUs();
433
- for (let i=0; i < numCPUs; i++) {
434
- this.#SpawnWorker();
435
- }
436
-
437
- this.#InitCluster(LogEx);
438
-
439
- cluster.on('listening', (worker, address) =>
440
- {
441
- LogEx(`Worker process ${worker.process.pid} is listening at address: ${JSON.stringify(address)}`);
442
- });
443
-
444
- //Setting up lifecycle event listeners for worker processes
445
- cluster.on('online', worker =>
446
- {
447
- LogEx(`Worker process ${worker.process.pid} is online`);
448
- });
449
-
450
- cluster.on('exit', (worker, code, signal) =>
451
- {
452
- if ((code !== null && code === 0) || (signal === 'SIGINT'))
453
- {
454
- LogEx(`Process ${worker.process.pid} terminated gracefully with code: ${code}, signal: ${signal}`.green);
455
- this.DecWorkers();
456
- } else if ((code !== null && code === 15) || (signal === 'SIGTERM'))
457
- {
458
- this.DecWorkers();
459
- LogEx(`Process ${worker.process.pid} terminated with code: ${code}, signal: ${signal}`.red);
460
- } else {
461
- this.DecWorkers();
462
- LogEx(`worker ${worker.process.pid} died`.red);
463
- LogEx(`code: ${code}`.red);
464
- LogEx(`signal: ${signal}`.red);
465
- LogEx('process terminated in an error state'.red);
466
- if (goptions.respawnOnFail === true)
467
- {
468
- LogEx(`Attemping to respawn worker`);
469
- this.#SpawnWorker();
470
- }
471
- }
472
- });
473
-
474
- // Terminate in order;
475
- // forked worker threads (send signal)
476
- // De-Register service
477
- // systeminformation observers
478
- // instrument timers (gauge etc.)
479
- // publisher
480
- // terminate UI (if loaded)
481
- const Terminate = async (signal: any) =>
482
- {
483
- if (this.#shuttingDown === false)
484
- {
485
- this.#shuttingDown = true;
486
-
487
- if (this.#checkLatency) {
488
- clearInterval(this.#checkLatency);
489
- this.#checkLatency = null;
490
- }
491
-
492
- await this.ProcessTerminate();
493
-
494
- await this.ProcessTerminating();
495
-
496
- if (this.GetUIController() !== null)
497
- {
498
- LogEx('Destroy the user interface controller.');
499
- this.GetUIController().DestroyUI();
500
- }
501
-
502
- if (signal) {
503
- LogEx(this.GetSignalColour(signal)(`Main Process (masterprocess): ${process.pid} received signal: ${signal}`));
504
- } else {
505
- LogEx(this.GetSignalColour(null)(`Main Process (masterprocess): ${process.pid} received Terminate without signal.`));
506
- }
507
-
508
- LogEx(`De-Registering service.`);
509
- //@@ De-register here ...
510
-
511
- if (this.#httpServer !== null) {
512
- LogEx(`Closing httpServer.`);
513
- await this.#httpServer.close();
514
- this.#httpServer = null;
515
- }
516
-
517
- LogEx(`Stopping instruments.`);
518
- //@@StopInstruments(this.instruments);
519
-
520
- //@@endpublish was here (and working ...)
521
-
522
- LogEx('Killing Workers.');
523
- this.KillWorkers(signal);
524
-
525
- if (this.options.useDatabase) {
526
- LogEx(`Ending database connections and pools.`);
527
- await this.TerminateDatabase();
528
- //await this.accessLayer.enddatabase();
529
- }
530
-
531
- // Now allow some time for the workers to die and send any remaining messages ...
532
- //if (this.InstrumentController && this.InstrumentController.Workers.length > 0) {
533
- if (this.InstrumentController) {
534
- LogEx(`Ending publisher.`);
535
- setTimeout(() => {
536
- if (this.InstrumentController) {
537
- this.InstrumentController.InstrumentTerminate();
538
- }
539
- }, 100);
540
- }
541
-
542
- if (this.options.processExitOnTerminate && this.options.processExitOnTerminate === true) {
543
- setTimeout(() => {
544
- LogEx(`Performing process.exit(0).`);
545
- process.exit(0);
546
- }, this.#childProcessExitTime + this.#masterProcessExitTime); // Give the workers time to terminate gracefully
547
- } else {
548
- LogEx(`Performing process.exit(0) - Immediate.`);
549
- }
550
- }
551
- }
552
-
553
- process.on('SIGINT', async () =>
554
- {
555
- await Terminate('SIGINT');
556
- });
557
-
558
- process.on('SIGTERM', async () =>
559
- {
560
- await Terminate('SIGTERM');
561
- });
562
-
563
- process.on('exit', (code) =>
564
- {
565
- if (code === 0)
566
- {
567
- LogEx(`Main Process: ${process.pid} terminated gracefully with code: ${code}`.green);
568
- } else {
569
- LogEx(`Main Process: ${process.pid} terminated with code: ${code}`.red);
570
- }
571
- });
572
-
573
- if (this.options.useLatency) {
574
- this.#checkLatency = setInterval(() => {
575
- this.#CheckLatency();
576
- }, 1000).unref();
577
- }
578
-
579
- this.MasterStarted();
580
-
581
- LogEx(`Master process:${process.pid} started`.green);
582
- }
583
-
584
- BroadcastDataToWorkers = (command: any, data: any) => {
585
- try {
586
- for (const id in cluster.workers) {
587
- try {
588
- //@@LogEx(`Sending message to worker PID: ${cluster.workers[id].process.pid}`.grey);
589
- (cluster.workers[id] as Worker).process.send( { command: command, data: data } );
590
- } catch (error) {
591
- //@@LogEx(error);
592
- }
593
- }
594
- } catch (error) {
595
- //@@LogEx(error);
596
- }
597
- }
598
- }