@mdf.js/service-registry
Version:
MMS - API - Service Registry
155 lines • 6.85 kB
JavaScript
;
/**
* Copyright 2024 Mytra Control S.L. All rights reserved.
*
* Use of this source code is governed by an MIT-style license that can be found in the LICENSE file
* or at https://opensource.org/licenses/MIT.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.MasterPort = void 0;
const tslib_1 = require("tslib");
const cluster_1 = tslib_1.__importDefault(require("cluster"));
const types_1 = require("../types");
const Port_1 = require("./Port");
/**
* MasterPort class manages the collection and aggregation of error records from worker processes
* in a clustered environment. It periodically requests error registries from each worker,
* aggregates the errors, and updates the main aggregator instance with the collected errors.
*
* Inherits from the Port class, utilizing its logging capabilities and defining additional
* mechanisms for inter-process communication and error aggregation specific to the master process.
*/
class MasterPort extends Port_1.Port {
/**
* Create an instance of errors manager in a master process
* @param aggregator - Aggregator instance to manage the errors
* @param logger - Logger instance for logging activities
* @param interval - interval in milliseconds between each error registry poll from workers.
*/
constructor(aggregator, logger, interval = types_1.DEFAULT_CONFIG_REGISTER_CLUSTER_UPDATE_INTERVAL) {
super(logger);
this.aggregator = aggregator;
this.interval = interval;
/** Request sequence number */
this.requestId = 0;
/**
* Sends a request to all worker processes to send their current error registries.
* Handles responses, timeouts, and updates the aggregator with aggregated errors from workers.
*/
this.onSendRequest = () => {
this.requestId = this.requestId + 1;
if (!Number.isFinite(this.requestId)) {
this.requestId = 0;
}
let pendingResponses = Object.keys(this.workers).length;
let timeOutHandler;
let updatedRegistries = [];
const onWorkerResponse = (worker, message) => {
if (message.requestId !== this.requestId) {
// Stryker disable next-line all
this.logger.debug(`Update response from worker [${worker.process.pid}] out of the valid period`);
return;
}
if (message.type === types_1.RegisterMessageType.RES) {
pendingResponses = pendingResponses - 1;
updatedRegistries = this.mergeErrors(updatedRegistries, worker, message.errors);
if (pendingResponses === 0 && timeOutHandler) {
onFinished();
}
}
};
const onTimeOut = () => {
// Stryker disable next-line all
this.logger.debug(`Timeout for update response from workers - ${pendingResponses} pending`);
onFinished();
};
const onFinished = () => {
// Stryker disable next-line all
this.logger.debug('Registry update from workers finished');
cluster_1.default.off('message', onWorkerResponse);
if (timeOutHandler) {
clearTimeout(timeOutHandler);
timeOutHandler = undefined;
}
this.aggregator.updateWorkersErrors(updatedRegistries);
};
timeOutHandler = setTimeout(onTimeOut, this.interval * 0.9);
cluster_1.default.on('message', onWorkerResponse);
for (const worker of Object.values(this.workers)) {
if (worker === null || worker === void 0 ? void 0 : worker.isConnected()) {
// Stryker disable next-line all
this.logger.debug(`Sending an errors register update request to worker [${worker.process.pid}]`);
worker.send({
type: types_1.RegisterMessageType.REQ,
requestId: this.requestId,
});
}
}
};
// Stryker disable next-line all
this.logger.debug(`New master port instance created: ${JSON.stringify({ interval })}`);
}
/**
* Starts the process of periodically polling error registries from worker processes.
* Ensures that only one polling mechanism is active at any given time.
*/
start() {
// Stryker disable next-line all
this.logger.debug('Starting errors registry polling in master process');
if (!this.timeInterval) {
this.onSendRequest();
this.timeInterval = setInterval(this.onSendRequest, this.interval);
}
}
/**
* Stops the polling of error registries from worker processes and clears the polling interval.
*/
stop() {
// Stryker disable next-line all
this.logger.debug('Stopping errors registry polling in master process');
if (this.timeInterval) {
clearInterval(this.timeInterval);
this.timeInterval = undefined;
}
}
/**
* Clears all error registries, both in the master and in all connected worker processes.
*/
clear() {
for (const worker of Object.values(this.workers)) {
if (worker === null || worker === void 0 ? void 0 : worker.isConnected()) {
// Stryker disable next-line all
this.logger.debug(`Sending an clear register request to worker [${worker.process.pid}]`);
worker.send({
type: types_1.RegisterMessageType.CLR_REQ,
});
}
}
this.aggregator.clear();
}
/**
* Merges the errors received from a worker process into the accumulated error records.
* Adds worker identification details to each error record for traceability.
* @param feed - feed to be merged with the errors from the worker
* @param worker - Worker that emit the errors
* @param workerErrors - errors from the worker
*/
mergeErrors(feed, worker, workerErrors) {
return feed.concat(workerErrors.map(error => {
return {
...error,
workerPid: worker.process.pid,
workerId: worker.id,
};
}));
}
/**
* Retrieves a dictionary of currently active worker processes.
* @returns A dictionary of Worker instances indexed by their cluster worker ID.
*/
get workers() {
return cluster_1.default.workers ? cluster_1.default.workers : {};
}
}
exports.MasterPort = MasterPort;
//# sourceMappingURL=MasterPort.js.map