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