@nsshunt/stsappframework 2.19.173 → 2.19.174

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.
@@ -1,28 +1,7 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
12
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
13
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
14
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
15
- };
16
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
17
- if (kind === "m") throw new TypeError("Private method is not writable");
18
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
19
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
20
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
21
- };
22
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
23
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
24
4
  };
25
- var _WorkerProcessBase_io, _WorkerProcessBase_httpServer, _WorkerProcessBase_expressServer, _WorkerProcessBase_inFlightMessage, _WorkerProcessBase_requestResponseMessageTimeout, _WorkerProcessBase_SendMessageToParentProcess, _WorkerProcessBase_SetupPrometheusEndPoints;
26
5
  Object.defineProperty(exports, "__esModule", { value: true });
27
6
  exports.WorkerProcessBase = void 0;
28
7
  const debug_1 = __importDefault(require("debug"));
@@ -46,307 +25,16 @@ const server_1 = require("./server");
46
25
  * @property {boolean} [wssServer=false] - Create a web socket server on this worker instance
47
26
  */
48
27
  class WorkerProcessBase extends processbase_1.ProcessBase {
28
+ #io = null;
29
+ #httpServer = null;
30
+ #expressServer = null;
31
+ #inFlightMessage = {};
32
+ #requestResponseMessageTimeout = 2000; //@@ config
49
33
  constructor(options) {
50
34
  super(options);
51
- _WorkerProcessBase_io.set(this, null);
52
- _WorkerProcessBase_httpServer.set(this, null);
53
- _WorkerProcessBase_expressServer.set(this, null);
54
- _WorkerProcessBase_inFlightMessage.set(this, {});
55
- _WorkerProcessBase_requestResponseMessageTimeout.set(this, 2000); //@@ config
56
- _WorkerProcessBase_SendMessageToParentProcess.set(this, (message) => {
57
- return new Promise((resolve, reject) => {
58
- if (__classPrivateFieldGet(this, _WorkerProcessBase_inFlightMessage, "f")[message.id]) {
59
- reject(`Message with id: [${message.id}] already exists within the Request/Response record structure`);
60
- }
61
- else {
62
- __classPrivateFieldGet(this, _WorkerProcessBase_inFlightMessage, "f")[message.id] = {
63
- iPCMessagePayload: Object.assign({}, message),
64
- cb: () => {
65
- const detail = __classPrivateFieldGet(this, _WorkerProcessBase_inFlightMessage, "f")[message.id].iPCMessagePayload.responseDetail;
66
- clearTimeout(__classPrivateFieldGet(this, _WorkerProcessBase_inFlightMessage, "f")[message.id].timeout);
67
- setTimeout(() => {
68
- delete __classPrivateFieldGet(this, _WorkerProcessBase_inFlightMessage, "f")[message.id];
69
- }, 0).unref();
70
- debug(`Resolving response message with id: [${message.id}] from parent process via IPC. Details: [${JSON.stringify(__classPrivateFieldGet(this, _WorkerProcessBase_inFlightMessage, "f")[message.id].iPCMessagePayload)}]`.green);
71
- resolve(detail);
72
- },
73
- timeout: setTimeout(() => {
74
- setTimeout(() => {
75
- delete __classPrivateFieldGet(this, _WorkerProcessBase_inFlightMessage, "f")[message.id];
76
- }, 0).unref();
77
- debug(`Timeout has occurred after: [${__classPrivateFieldGet(this, _WorkerProcessBase_requestResponseMessageTimeout, "f")}]ms with message id: [${message.id}]. Details: [${JSON.stringify(__classPrivateFieldGet(this, _WorkerProcessBase_inFlightMessage, "f")[message.id].iPCMessagePayload)}]`.red);
78
- reject('Did not receive response form parent process.');
79
- }, __classPrivateFieldGet(this, _WorkerProcessBase_requestResponseMessageTimeout, "f")) // max message timeout allowed
80
- };
81
- debug(`Sending message with id: [${message.id}] to parent process via IPC. Details: [${JSON.stringify(__classPrivateFieldGet(this, _WorkerProcessBase_inFlightMessage, "f")[message.id].iPCMessagePayload)}]`.yellow);
82
- process.send(message);
83
- }
84
- });
85
- }
86
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
- );
88
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
- this.AddWorker = (options) => __awaiter(this, void 0, void 0, function* () {
90
- const workerResponse = yield __classPrivateFieldGet(this, _WorkerProcessBase_SendMessageToParentProcess, "f").call(this, {
91
- requestResponse: true,
92
- id: (0, uuid_1.v4)(),
93
- command: commonTypes_1.IPCMessageCommand.AddWorker,
94
- requestDetail: {
95
- options
96
- }
97
- });
98
- return workerResponse.workerId;
99
- });
100
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
101
- this.DeleteWorker = (workerId, options) => __awaiter(this, void 0, void 0, function* () {
102
- const workerResponse = yield __classPrivateFieldGet(this, _WorkerProcessBase_SendMessageToParentProcess, "f").call(this, {
103
- requestResponse: true,
104
- id: (0, uuid_1.v4)(),
105
- command: commonTypes_1.IPCMessageCommand.DeleteWorker,
106
- requestDetail: {
107
- options,
108
- workerId
109
- }
110
- });
111
- return workerResponse;
112
- });
113
- // Setup server to Prometheus scrapes:
114
- _WorkerProcessBase_SetupPrometheusEndPoints.set(this, (expressServer) => {
115
- // AggregatorRegistry is required here in the worker as well as the master in order for prom-client to work correctly.
116
- new prom_client_1.AggregatorRegistry();
117
- const prefix = 'sts_';
118
- (0, prom_client_1.collectDefaultMetrics)({
119
- labels: { NODE_APP_INSTANCE: process.pid },
120
- prefix: prefix
121
- });
122
- const c = new prom_client_1.Counter({
123
- name: 'sts_test_counter',
124
- help: 'Example of a counter',
125
- labelNames: ['code'],
126
- });
127
- setInterval(() => {
128
- c.inc({ code: 200 });
129
- }, 1000).unref();
130
- setInterval(() => {
131
- c.inc({ code: 400 });
132
- c.inc({ code: 'worker_' + process.pid });
133
- }, 500).unref();
134
- expressServer.get('/metrics', (req, res) => __awaiter(this, void 0, void 0, function* () {
135
- try {
136
- res.set('Content-Type', prom_client_1.register.contentType);
137
- res.end(yield prom_client_1.register.metrics());
138
- }
139
- catch (ex) {
140
- res.status(500).end(ex);
141
- }
142
- }));
143
- expressServer.get('/metrics/counter', (req, res) => __awaiter(this, void 0, void 0, function* () {
144
- try {
145
- res.set('Content-Type', prom_client_1.register.contentType);
146
- res.end(yield prom_client_1.register.getSingleMetricAsString('test_counter'));
147
- }
148
- catch (ex) {
149
- res.status(500).end(ex);
150
- }
151
- }));
152
- });
153
- this.SetupServer = () => __awaiter(this, void 0, void 0, function* () {
154
- this.SetupInstrumentation();
155
- setTimeout(() => {
156
- this.SetupServerEx();
157
- }, 100);
158
- });
159
- this.SetupServerEx = () => __awaiter(this, void 0, void 0, function* () {
160
- this.ProcessStartup();
161
- if (this.options.expressServerRouteFactory || this.options.expressServerRouteStaticFactory) {
162
- __classPrivateFieldSet(this, _WorkerProcessBase_expressServer, new server_1.STSExpressServer(this.options, this), "f");
163
- }
164
- const LogEx = this.LogEx;
165
- /*
166
- if (this.instruments !== null) {
167
- this.instruments[Gauge.LOGGER].consoleLogging = this.options.consoleLogging;
168
- this.instruments[Gauge.LOGGER].instrumentLogging = this.options.instrumentLogging;
169
- }
170
- */
171
- LogEx(`Worker instance starting. Service instance Id: [${this.options.serviceInstanceId}]`);
172
- __classPrivateFieldSet(this, _WorkerProcessBase_httpServer, null, "f");
173
- let shuttingDown = false;
174
- const Terminate = (performExit = true) => __awaiter(this, void 0, void 0, function* () {
175
- if (shuttingDown === false) {
176
- shuttingDown = true;
177
- yield this.ProcessTerminate();
178
- this.ProcessTerminating();
179
- LogEx(`Stopping instruments.`);
180
- //@@StopInstruments(this.instruments);
181
- if (this.options.wssServer === true && __classPrivateFieldGet(this, _WorkerProcessBase_io, "f") !== null) {
182
- LogEx(`Disconnect Sockets.`);
183
- if (this.socketIoHelper !== null) {
184
- this.socketIoHelper.DisconnectSockets();
185
- }
186
- else {
187
- __classPrivateFieldGet(this, _WorkerProcessBase_io, "f").disconnectSockets();
188
- }
189
- this.socketIoHelper = null;
190
- __classPrivateFieldSet(this, _WorkerProcessBase_io, null, "f");
191
- }
192
- if (this.options.httpServer === true) {
193
- LogEx(`Closing httpServer.`);
194
- yield __classPrivateFieldGet(this, _WorkerProcessBase_httpServer, "f").close();
195
- }
196
- if (this.options.useDatabase) {
197
- LogEx(`Ending database connections and pools.`);
198
- yield this.TerminateDatabase();
199
- //await this.accessLayer.enddatabase();
200
- }
201
- LogEx(`Performing exit value: [${performExit}]`);
202
- if (performExit) {
203
- LogEx(`Process will self terminate with process.exit(0).`);
204
- }
205
- else {
206
- LogEx(`Child process will not self terminate. Terminate will be handled by master process.`);
207
- }
208
- if (this.InstrumentController && this.InstrumentController.Workers.length > 0) {
209
- setTimeout(() => {
210
- if (this.InstrumentController && this.InstrumentController.Workers.length > 0) {
211
- this.InstrumentController.InstrumentTerminate();
212
- }
213
- }, 100);
214
- }
215
- //@@ always return here appears to always cleanly exit
216
- // and cleanly exit from socket.io cluster adaptor
217
- // without return here, socket.io cluster adaptor terminates in an error state
218
- // as the implementation relies on cluster.on to send messages to worker threads
219
- // but these have already been closed from the process.exit(0) below.
220
- yield (0, stsutils_1.Sleep)(1000); // Allow socket.io time to clean-up
221
- if (performExit) {
222
- setTimeout(() => {
223
- process.exit(0);
224
- }, 0);
225
- }
226
- }
227
- else {
228
- LogEx(`Process already terminating.`);
229
- }
230
- });
231
- // Receive messages from the master process.
232
- //const self = this;
233
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
234
- process.on('message', (msg) => __awaiter(this, void 0, void 0, function* () {
235
- if (msg.requestResponse) {
236
- const iPCMessagePayload = msg;
237
- if (iPCMessagePayload.id) {
238
- if (__classPrivateFieldGet(this, _WorkerProcessBase_inFlightMessage, "f")[iPCMessagePayload.id]) {
239
- const responseMessage = __classPrivateFieldGet(this, _WorkerProcessBase_inFlightMessage, "f")[iPCMessagePayload.id];
240
- responseMessage.iPCMessagePayload.responseDetail = Object.assign({}, iPCMessagePayload.responseDetail);
241
- responseMessage.cb();
242
- }
243
- else {
244
- throw new Error(`Could not find Request/Response message with id: [${iPCMessagePayload.id}]`);
245
- }
246
- }
247
- else {
248
- throw new Error(`Message does not have id attribute. [${JSON.stringify(iPCMessagePayload)}]`);
249
- }
250
- return;
251
- }
252
- if (msg.command) //@@ constants
253
- {
254
- switch (msg.command) {
255
- case 'Terminate':
256
- LogEx((`Received ` + colors_1.default.bold(`Terminate`.italic) + ` message from master thread`).gray);
257
- yield Terminate(false); // Don't kill the child process here, the master will take care of that ...
258
- break;
259
- case 'TerminateAndKill':
260
- LogEx((`Received ` + colors_1.default.bold(`Terminate`.italic) + ` message from master thread`).gray);
261
- yield Terminate(true);
262
- break;
263
- case 'Message':
264
- LogEx((`Received ` + colors_1.default.bold(`Message`.italic) + ` message from master thread`).gray);
265
- this.ReceivedMessageFromMaster(msg.data);
266
- break;
267
- case 'Response': // General response to a req/response interaction
268
- msg.details;
269
- }
270
- }
271
- }));
272
- if (this.options.httpServer === true) {
273
- if (this.options.httpsServer === true) {
274
- const options = {
275
- key: fs_1.default.readFileSync(this.options.httpsServerKeyPath),
276
- cert: fs_1.default.readFileSync(this.options.httpsServerCertificatePath)
277
- };
278
- __classPrivateFieldSet(this, _WorkerProcessBase_httpServer, (0, https_1.createServer)(options, __classPrivateFieldGet(this, _WorkerProcessBase_expressServer, "f").App), "f");
279
- }
280
- else {
281
- __classPrivateFieldSet(this, _WorkerProcessBase_httpServer, (0, http_1.createServer)(__classPrivateFieldGet(this, _WorkerProcessBase_expressServer, "f").App), "f");
282
- }
283
- //this.#httpServer.maxConnections = 50;
284
- if (this.options.prometheusSupport === true) {
285
- __classPrivateFieldGet(this, _WorkerProcessBase_SetupPrometheusEndPoints, "f").call(this, __classPrivateFieldGet(this, _WorkerProcessBase_expressServer, "f").App);
286
- }
287
- // Setup the web socket server (using socket.io) if enabled.
288
- if (this.options.wssServer === true) {
289
- // socket.io
290
- // WebSocket
291
- const options = {
292
- transports: ["websocket"] // or [ "websocket", "polling" ] (to use long-poolling. Note that the order matters)
293
- // The default path is /socket.io
294
- // This can be changed with the path option as shown below
295
- //,path: '/zzz'
296
- };
297
- //this.#io = require("socket.io")(this.#httpServer, options);
298
- __classPrivateFieldSet(this, _WorkerProcessBase_io, new socket_io_1.Server(__classPrivateFieldGet(this, _WorkerProcessBase_httpServer, "f"), options), "f");
299
- __classPrivateFieldGet(this, _WorkerProcessBase_io, "f").adapter((0, cluster_adapter_1.createAdapter)());
300
- // To use a seperate socket server, the code below can be applied.
301
- // this.#io = require("socket.io")(options);
302
- // this.#io.adapter(createAdapter());
303
- // this.#io.listen(3006);
304
- // LogEx(`socket.io init`);
305
- __classPrivateFieldGet(this, _WorkerProcessBase_io, "f").engine.on("connection_error", (err) => {
306
- LogEx(err.req); // the request object
307
- LogEx(err.code); // the error code, for example 1
308
- LogEx(err.message); // the error message, for example "Session ID unknown"
309
- LogEx(err.context); // some additional error context
310
- });
311
- }
312
- try {
313
- // https://stackoverflow.com/questions/21342828/node-express-unix-domain-socket-permissions
314
- //@@httpServer.listen('/tmp/stsrest01.sock').on('listening', () =>
315
- //@@httpServer.listen('/var/run/sts/stsrest01.sock').on('listening', () =>
316
- __classPrivateFieldGet(this, _WorkerProcessBase_httpServer, "f").listen(this.options.listenPort, () => {
317
- //@@chmodSync(this.options.port, 511);
318
- }).on('listening', () => {
319
- LogEx(`live on ${this.options.endpoint}:${this.options.listenPort}${this.options.apiRoot}`);
320
- });
321
- }
322
- catch (error) {
323
- console.error(error);
324
- throw error;
325
- }
326
- }
327
- /*
328
- if (this.publishBroker !== null) {
329
- setTimeout(() => {
330
- this.publishBroker.StartPublish();
331
- }, 0);
332
- }
333
- */
334
- // Signal Codes
335
- // https://en.wikipedia.org/wiki/Signal_(IPC)
336
- process.on('SIGTERM', () => __awaiter(this, void 0, void 0, function* () {
337
- LogEx(`SIGTERM signal received for worker: ${process.pid}`);
338
- yield Terminate();
339
- }));
340
- process.on('SIGINT', () => __awaiter(this, void 0, void 0, function* () {
341
- LogEx(`SIGINT signal received for worker: ${process.pid}`);
342
- yield Terminate();
343
- }));
344
- this.WorkerStarted();
345
- LogEx(`Worker process:${process.pid} started`.green);
346
- });
347
35
  }
348
36
  get httpServer() {
349
- return __classPrivateFieldGet(this, _WorkerProcessBase_httpServer, "f");
37
+ return this.#httpServer;
350
38
  }
351
39
  WorkerStarted() {
352
40
  return null;
@@ -364,15 +52,303 @@ class WorkerProcessBase extends processbase_1.ProcessBase {
364
52
  });
365
53
  }
366
54
  get io() {
367
- return __classPrivateFieldGet(this, _WorkerProcessBase_io, "f");
55
+ return this.#io;
368
56
  }
57
+ #SendMessageToParentProcess = (message) => {
58
+ return new Promise((resolve, reject) => {
59
+ if (this.#inFlightMessage[message.id]) {
60
+ reject(`Message with id: [${message.id}] already exists within the Request/Response record structure`);
61
+ }
62
+ else {
63
+ this.#inFlightMessage[message.id] = {
64
+ iPCMessagePayload: { ...message },
65
+ cb: () => {
66
+ const detail = this.#inFlightMessage[message.id].iPCMessagePayload.responseDetail;
67
+ clearTimeout(this.#inFlightMessage[message.id].timeout);
68
+ setTimeout(() => {
69
+ delete this.#inFlightMessage[message.id];
70
+ }, 0).unref();
71
+ debug(`Resolving response message with id: [${message.id}] from parent process via IPC. Details: [${JSON.stringify(this.#inFlightMessage[message.id].iPCMessagePayload)}]`.green);
72
+ resolve(detail);
73
+ },
74
+ timeout: setTimeout(() => {
75
+ setTimeout(() => {
76
+ delete this.#inFlightMessage[message.id];
77
+ }, 0).unref();
78
+ debug(`Timeout has occurred after: [${this.#requestResponseMessageTimeout}]ms with message id: [${message.id}]. Details: [${JSON.stringify(this.#inFlightMessage[message.id].iPCMessagePayload)}]`.red);
79
+ reject('Did not receive response form parent process.');
80
+ }, this.#requestResponseMessageTimeout) // max message timeout allowed
81
+ };
82
+ debug(`Sending message with id: [${message.id}] to parent process via IPC. Details: [${JSON.stringify(this.#inFlightMessage[message.id].iPCMessagePayload)}]`.yellow);
83
+ process.send(message);
84
+ }
85
+ });
86
+ };
87
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
88
+ AddWorker = async (options) => {
89
+ const workerResponse = await this.#SendMessageToParentProcess({
90
+ requestResponse: true,
91
+ id: (0, uuid_1.v4)(),
92
+ command: commonTypes_1.IPCMessageCommand.AddWorker,
93
+ requestDetail: {
94
+ options
95
+ }
96
+ });
97
+ return workerResponse.workerId;
98
+ };
99
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
+ DeleteWorker = async (workerId, options) => {
101
+ const workerResponse = await this.#SendMessageToParentProcess({
102
+ requestResponse: true,
103
+ id: (0, uuid_1.v4)(),
104
+ command: commonTypes_1.IPCMessageCommand.DeleteWorker,
105
+ requestDetail: {
106
+ options,
107
+ workerId
108
+ }
109
+ });
110
+ return workerResponse;
111
+ };
369
112
  ProcessTerminating() {
370
113
  return null;
371
114
  }
115
+ // Setup server to Prometheus scrapes:
116
+ #SetupPrometheusEndPoints = (expressServer) => {
117
+ // AggregatorRegistry is required here in the worker as well as the master in order for prom-client to work correctly.
118
+ new prom_client_1.AggregatorRegistry();
119
+ const prefix = 'sts_';
120
+ (0, prom_client_1.collectDefaultMetrics)({
121
+ labels: { NODE_APP_INSTANCE: process.pid },
122
+ prefix: prefix
123
+ });
124
+ const c = new prom_client_1.Counter({
125
+ name: 'sts_test_counter',
126
+ help: 'Example of a counter',
127
+ labelNames: ['code'],
128
+ });
129
+ setInterval(() => {
130
+ c.inc({ code: 200 });
131
+ }, 1000).unref();
132
+ setInterval(() => {
133
+ c.inc({ code: 400 });
134
+ c.inc({ code: 'worker_' + process.pid });
135
+ }, 500).unref();
136
+ expressServer.get('/metrics', async (req, res) => {
137
+ try {
138
+ res.set('Content-Type', prom_client_1.register.contentType);
139
+ res.end(await prom_client_1.register.metrics());
140
+ }
141
+ catch (ex) {
142
+ res.status(500).end(ex);
143
+ }
144
+ });
145
+ expressServer.get('/metrics/counter', async (req, res) => {
146
+ try {
147
+ res.set('Content-Type', prom_client_1.register.contentType);
148
+ res.end(await prom_client_1.register.getSingleMetricAsString('test_counter'));
149
+ }
150
+ catch (ex) {
151
+ res.status(500).end(ex);
152
+ }
153
+ });
154
+ };
372
155
  get expressServer() {
373
- return __classPrivateFieldGet(this, _WorkerProcessBase_expressServer, "f");
156
+ return this.#expressServer;
374
157
  }
158
+ SetupServer = async () => {
159
+ this.SetupInstrumentation();
160
+ setTimeout(() => {
161
+ this.SetupServerEx();
162
+ }, 100);
163
+ };
164
+ SetupServerEx = async () => {
165
+ this.ProcessStartup();
166
+ if (this.options.expressServerRouteFactory || this.options.expressServerRouteStaticFactory) {
167
+ this.#expressServer = new server_1.STSExpressServer(this.options, this);
168
+ }
169
+ const LogEx = this.LogEx;
170
+ /*
171
+ if (this.instruments !== null) {
172
+ this.instruments[Gauge.LOGGER].consoleLogging = this.options.consoleLogging;
173
+ this.instruments[Gauge.LOGGER].instrumentLogging = this.options.instrumentLogging;
174
+ }
175
+ */
176
+ LogEx(`Worker instance starting. Service instance Id: [${this.options.serviceInstanceId}]`);
177
+ this.#httpServer = null;
178
+ let shuttingDown = false;
179
+ const Terminate = async (performExit = true) => {
180
+ if (shuttingDown === false) {
181
+ shuttingDown = true;
182
+ await this.ProcessTerminate();
183
+ this.ProcessTerminating();
184
+ LogEx(`Stopping instruments.`);
185
+ //@@StopInstruments(this.instruments);
186
+ if (this.options.wssServer === true && this.#io !== null) {
187
+ LogEx(`Disconnect Sockets.`);
188
+ if (this.socketIoHelper !== null) {
189
+ this.socketIoHelper.DisconnectSockets();
190
+ }
191
+ else {
192
+ this.#io.disconnectSockets();
193
+ }
194
+ this.socketIoHelper = null;
195
+ this.#io = null;
196
+ }
197
+ if (this.options.httpServer === true) {
198
+ LogEx(`Closing httpServer.`);
199
+ await this.#httpServer.close();
200
+ }
201
+ if (this.options.useDatabase) {
202
+ LogEx(`Ending database connections and pools.`);
203
+ await this.TerminateDatabase();
204
+ //await this.accessLayer.enddatabase();
205
+ }
206
+ LogEx(`Performing exit value: [${performExit}]`);
207
+ if (performExit) {
208
+ LogEx(`Process will self terminate with process.exit(0).`);
209
+ }
210
+ else {
211
+ LogEx(`Child process will not self terminate. Terminate will be handled by master process.`);
212
+ }
213
+ if (this.InstrumentController && this.InstrumentController.Workers.length > 0) {
214
+ setTimeout(() => {
215
+ if (this.InstrumentController && this.InstrumentController.Workers.length > 0) {
216
+ this.InstrumentController.InstrumentTerminate();
217
+ }
218
+ }, 100);
219
+ }
220
+ //@@ always return here appears to always cleanly exit
221
+ // and cleanly exit from socket.io cluster adaptor
222
+ // without return here, socket.io cluster adaptor terminates in an error state
223
+ // as the implementation relies on cluster.on to send messages to worker threads
224
+ // but these have already been closed from the process.exit(0) below.
225
+ await (0, stsutils_1.Sleep)(1000); // Allow socket.io time to clean-up
226
+ if (performExit) {
227
+ setTimeout(() => {
228
+ process.exit(0);
229
+ }, 0);
230
+ }
231
+ }
232
+ else {
233
+ LogEx(`Process already terminating.`);
234
+ }
235
+ };
236
+ // Receive messages from the master process.
237
+ //const self = this;
238
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
239
+ process.on('message', async (msg) => {
240
+ if (msg.requestResponse) {
241
+ const iPCMessagePayload = msg;
242
+ if (iPCMessagePayload.id) {
243
+ if (this.#inFlightMessage[iPCMessagePayload.id]) {
244
+ const responseMessage = this.#inFlightMessage[iPCMessagePayload.id];
245
+ responseMessage.iPCMessagePayload.responseDetail = { ...iPCMessagePayload.responseDetail };
246
+ responseMessage.cb();
247
+ }
248
+ else {
249
+ throw new Error(`Could not find Request/Response message with id: [${iPCMessagePayload.id}]`);
250
+ }
251
+ }
252
+ else {
253
+ throw new Error(`Message does not have id attribute. [${JSON.stringify(iPCMessagePayload)}]`);
254
+ }
255
+ return;
256
+ }
257
+ if (msg.command) //@@ constants
258
+ {
259
+ switch (msg.command) {
260
+ case 'Terminate':
261
+ LogEx((`Received ` + colors_1.default.bold(`Terminate`.italic) + ` message from master thread`).gray);
262
+ await Terminate(false); // Don't kill the child process here, the master will take care of that ...
263
+ break;
264
+ case 'TerminateAndKill':
265
+ LogEx((`Received ` + colors_1.default.bold(`Terminate`.italic) + ` message from master thread`).gray);
266
+ await Terminate(true);
267
+ break;
268
+ case 'Message':
269
+ LogEx((`Received ` + colors_1.default.bold(`Message`.italic) + ` message from master thread`).gray);
270
+ this.ReceivedMessageFromMaster(msg.data);
271
+ break;
272
+ case 'Response': // General response to a req/response interaction
273
+ msg.details;
274
+ }
275
+ }
276
+ });
277
+ if (this.options.httpServer === true) {
278
+ if (this.options.httpsServer === true) {
279
+ const options = {
280
+ key: fs_1.default.readFileSync(this.options.httpsServerKeyPath),
281
+ cert: fs_1.default.readFileSync(this.options.httpsServerCertificatePath)
282
+ };
283
+ this.#httpServer = (0, https_1.createServer)(options, this.#expressServer.App);
284
+ }
285
+ else {
286
+ this.#httpServer = (0, http_1.createServer)(this.#expressServer.App);
287
+ }
288
+ //this.#httpServer.maxConnections = 50;
289
+ if (this.options.prometheusSupport === true) {
290
+ this.#SetupPrometheusEndPoints(this.#expressServer.App);
291
+ }
292
+ // Setup the web socket server (using socket.io) if enabled.
293
+ if (this.options.wssServer === true) {
294
+ // socket.io
295
+ // WebSocket
296
+ const options = {
297
+ transports: ["websocket"] // or [ "websocket", "polling" ] (to use long-poolling. Note that the order matters)
298
+ // The default path is /socket.io
299
+ // This can be changed with the path option as shown below
300
+ //,path: '/zzz'
301
+ };
302
+ //this.#io = require("socket.io")(this.#httpServer, options);
303
+ this.#io = new socket_io_1.Server(this.#httpServer, options);
304
+ this.#io.adapter((0, cluster_adapter_1.createAdapter)());
305
+ // To use a seperate socket server, the code below can be applied.
306
+ // this.#io = require("socket.io")(options);
307
+ // this.#io.adapter(createAdapter());
308
+ // this.#io.listen(3006);
309
+ // LogEx(`socket.io init`);
310
+ this.#io.engine.on("connection_error", (err) => {
311
+ LogEx(err.req); // the request object
312
+ LogEx(err.code); // the error code, for example 1
313
+ LogEx(err.message); // the error message, for example "Session ID unknown"
314
+ LogEx(err.context); // some additional error context
315
+ });
316
+ }
317
+ try {
318
+ // https://stackoverflow.com/questions/21342828/node-express-unix-domain-socket-permissions
319
+ //@@httpServer.listen('/tmp/stsrest01.sock').on('listening', () =>
320
+ //@@httpServer.listen('/var/run/sts/stsrest01.sock').on('listening', () =>
321
+ this.#httpServer.listen(this.options.listenPort, () => {
322
+ //@@chmodSync(this.options.port, 511);
323
+ }).on('listening', () => {
324
+ LogEx(`live on ${this.options.endpoint}:${this.options.listenPort}${this.options.apiRoot}`);
325
+ });
326
+ }
327
+ catch (error) {
328
+ console.error(error);
329
+ throw error;
330
+ }
331
+ }
332
+ /*
333
+ if (this.publishBroker !== null) {
334
+ setTimeout(() => {
335
+ this.publishBroker.StartPublish();
336
+ }, 0);
337
+ }
338
+ */
339
+ // Signal Codes
340
+ // https://en.wikipedia.org/wiki/Signal_(IPC)
341
+ process.on('SIGTERM', async () => {
342
+ LogEx(`SIGTERM signal received for worker: ${process.pid}`);
343
+ await Terminate();
344
+ });
345
+ process.on('SIGINT', async () => {
346
+ LogEx(`SIGINT signal received for worker: ${process.pid}`);
347
+ await Terminate();
348
+ });
349
+ this.WorkerStarted();
350
+ LogEx(`Worker process:${process.pid} started`.green);
351
+ };
375
352
  }
376
353
  exports.WorkerProcessBase = WorkerProcessBase;
377
- _WorkerProcessBase_io = new WeakMap(), _WorkerProcessBase_httpServer = new WeakMap(), _WorkerProcessBase_expressServer = new WeakMap(), _WorkerProcessBase_inFlightMessage = new WeakMap(), _WorkerProcessBase_requestResponseMessageTimeout = new WeakMap(), _WorkerProcessBase_SendMessageToParentProcess = new WeakMap(), _WorkerProcessBase_SetupPrometheusEndPoints = new WeakMap();
378
354
  //# sourceMappingURL=workerprocessbase.js.map