@vtex/api
Version:
VTEX I/O API client
90 lines (89 loc) • 3.64 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.startMaster = void 0;
const cluster_1 = __importDefault(require("cluster"));
const os_1 = require("os");
const constants_1 = require("../constants");
const logger_1 = require("./logger");
const listeners_1 = require("./worker/listeners");
const statusTrack_1 = require("./worker/runtime/statusTrack");
let handledSignal;
const onMessage = (worker, message) => {
if ((0, logger_1.isLog)(message)) {
(0, logger_1.logOnceToDevConsole)(message.message, message.level);
}
else if ((0, statusTrack_1.isStatusTrackBroadcast)(message)) {
(0, statusTrack_1.trackStatus)();
(0, statusTrack_1.broadcastStatusTrack)();
}
else {
listeners_1.logger.warn({
content: message,
message: 'Worker sent message',
pid: worker.process.pid,
});
}
};
const onExit = (worker, code, signal) => {
if (!constants_1.LINKED && worker.exitedAfterDisconnect === false) {
listeners_1.logger.error({
code,
message: 'Worker Died',
pid: worker.process.pid,
signal,
});
cluster_1.default.fork();
}
const exitOn = ['SIGTERM', 'SIGINT'];
if (handledSignal && exitOn.includes(handledSignal) && Object.keys(cluster_1.default.workers).length === 0) {
process.exit(os_1.constants.signals[handledSignal]);
}
};
let workersOnline = 0;
const onOnline = (worker) => {
console.log('Worker ' + worker.process.pid + ' is listening');
workersOnline += 1;
if (workersOnline === 1) {
worker.send(constants_1.UP_SIGNAL);
}
};
const GRACEFULLY_SHUTDOWN_TIMEOUT_S = 30;
const SIGINT_TIMEOUT_S = 1;
const handleSignal = (timeout) => (signal) => {
// For each worker, let's try to kill it gracefully
Object.values(cluster_1.default.workers).forEach((worker) => worker === null || worker === void 0 ? void 0 : worker.kill(signal));
// Let's raise the flag to kill the master process after all workers have died
handledSignal = signal;
// Let's wait for all in-flight requests finish before send any kill signal
const waitTimeToForceKill = timeout * 1e3;
// Force workers and master to die after a graceful timeout
setTimeout(() => {
Object.values(cluster_1.default.workers).forEach((worker) => worker === null || worker === void 0 ? void 0 : worker.process.kill('SIGKILL'));
process.exit(os_1.constants.signals[signal]);
}, waitTimeToForceKill);
};
const startMaster = (service) => {
const { workers: numWorkers, timeout = GRACEFULLY_SHUTDOWN_TIMEOUT_S } = service;
if (service.deterministicVary) {
process.env.DETERMINISTIC_VARY = 'true';
}
// Setup dubugger
if (constants_1.LINKED) {
cluster_1.default.setupMaster({ inspectPort: constants_1.INSPECT_DEBUGGER_PORT });
}
const shutdownTimeout = Math.max(GRACEFULLY_SHUTDOWN_TIMEOUT_S, timeout);
console.log(`Spawning ${numWorkers} workers`);
console.log(`Using ${shutdownTimeout} seconds as worker graceful shutdown timeout`);
for (let i = 0; i < numWorkers; i++) {
cluster_1.default.fork();
}
cluster_1.default.on('online', onOnline);
cluster_1.default.on('exit', onExit);
cluster_1.default.on('message', onMessage);
process.on('SIGINT', handleSignal(SIGINT_TIMEOUT_S));
process.on('SIGTERM', handleSignal(shutdownTimeout));
};
exports.startMaster = startMaster;
;