UNPKG

@vtex/api

Version:
90 lines (89 loc) 3.64 kB
"use strict"; 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;