function destroyWorker(worker, exitCode, signal, instructions) { exitCode = typeof exitCode === 'number' ? exitCode : signal ? 128: 0; var config = this._privateData.config; var workerPid = worker.pid; // Sound the death knell this.emit('end', { type: 'end', role: 'worker', id: workerPid, owner: process.pid, data: { reason: exitCode !== 0 ? 'fired' : 'quit', exitCode: exitCode, duration: Date.now() - this._privateData.workerStartTimes[workerPid] } }); // See if there are other workers remaining var hasWorkersLeft = false; for (var workerId in this._privateData.workers) { if (this._privateData.workers[workerId].pid !== workerPid) { hasWorkersLeft = true; break; } } // Clear any remaining timeouts var workerTimeoutId = this._privateData.workerTimeoutIds[workerPid]; if (workerTimeoutId) { safe.clearTimeout(workerTimeoutId); workerTimeoutId = null; } // Clean up storage delete this._privateData.workerStartTimes[workerPid]; delete this._privateData.workerTimeoutIds[workerPid]; delete this._privateData.workers[workerPid]; // Reinforcements!!! Rise from the ashes! // Create another Worker process when one Worker exits. if (config.continuous === true) { var createWorkerFn = createWorker.bind(this, instructions); if (config.stagger === true && typeof config.staggeredStart === 'number' && config.staggeredStart >= 0) { safe.setTimeout(createWorkerFn, config.staggeredStart); } else { process.nextTick(createWorkerFn); } } // Legion itself should bail out if no workers remain else if (!hasWorkersLeft) { die.call(this, exitCode); } }
ReverseProxy.prototype.unregister = function (src, target) { if (this.opts.cluster && cluster.isMaster) return this; if (!src) { return this; } src = prepareUrl(src); var routes = this.routing[src.hostname] || []; var pathname = src.pathname || '/'; var i; for (i = 0; i < routes.length; i++) { if (routes[i].path === pathname) { break; } } if (i < routes.length) { var route = routes[i]; if (target) { target = prepareUrl(target); _.remove(route.urls, function (url) { return url.href === target.href; }); } else { route.urls = []; } if (route.urls.length === 0) { routes.splice(i, 1); var certs = this.certs; if (certs) { if (certs[src.hostname] && certs[src.hostname].renewalTimeout) { safe.clearTimeout(certs[src.hostname].renewalTimeout); } delete certs[src.hostname]; } } this.log && this.log.info({ from: src, to: target }, 'Unregistered a route'); } return this; };
// // Whether natural or at the hand of our enemy, we all eventually meet our end. // function die(exitCode) { var theExitCode = this._privateData.theExitCode; var wasExitingAlready = typeof theExitCode === 'number'; var finalExitCode = wasExitingAlready ? theExitCode : typeof exitCode === 'number' ? exitCode : 0; // Sound the death knell this.emit('end', { type: 'end', role: 'legion', id: process.pid, owner: null, data: { reason: finalExitCode !== 0 ? 'fired' : 'quit', exitCode: finalExitCode, duration: Date.now() - this._privateData.startTime } }); // Clear any timeouts var maxTimeoutId = this._privateData.maxTimeoutId; if (maxTimeoutId) { safe.clearTimeout(maxTimeoutId); maxTimeoutId = null; } delete this._privateData.maxTimeoutId; // Clean up this._privateData.startTime = null; this._privateData.theExitCode = null; this._privateData.alreadyDead = true; // Exit forcibly but only if someone else didn't already invoke the exit if (!wasExitingAlready) { process.exit(finalExitCode); } return this; };
Legion.prototype.exit = function(exitCode) { // Die, workers! Die! var worker, workerPid; for (var workerId in this._privateData.workers) { worker = this._privateData.workers[workerId]; workerPid = worker.pid; worker.kill('SIGINT'); // The above `kill` calls will NOT react synchronously, so // we also need to manually announce the Workers' exit for them // before they ACTUALLY exit this.emit('end', { type: 'end', role: 'worker', id: workerPid, owner: process.pid, data: { reason: exitCode !== 0 ? 'fired' : 'quit', exitCode: exitCode, duration: Date.now() - this._privateData.workerStartTimes[workerPid] } }); // Clear any remaining timeouts var workerTimeoutId = this._privateData.workerTimeoutIds[workerPid]; if (workerTimeoutId) { safe.clearTimeout(workerTimeoutId); workerTimeoutId = null; } // Clean up storage delete this._privateData.workerStartTimes[workerPid]; delete this._privateData.workerTimeoutIds[workerPid]; delete this._privateData.workers[workerPid]; } return die.call(this, exitCode); };