Files
genieacs/lib/cluster.js
T

142 lines
3.3 KiB
JavaScript

/**
* Copyright 2013-2017 Zaid Abdulla
*
* GenieACS is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* GenieACS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
const cluster = require("cluster");
const logger = require("./logger");
const VERSION = require("../package.json").version;
function getDependencyVersions() {
let dependencies = [`node@${process.versions.node}`];
try {
let npmls = JSON.parse(require("child_process").execSync("npm ls --prod --json"));
for (let k in npmls.dependencies)
dependencies.push(`${k}@${npmls.dependencies[k].version}`);
} catch (err) {}
return dependencies.join(",");
}
function getConfig() {
let conf = [];
const keys = Object.keys(process.env);
for (let k of keys)
if (k.startsWith("GENIEACS_"))
conf.push(`${k.slice(9)}=${process.env[k]}`);
return conf.join(",");
}
function restartWorker(worker, code, signal) {
let msg = {
message: "Worker died",
pid: worker.process.pid
};
if (code != null)
msg.exitCode = code;
if (signal != null)
msg.signal = signal;
logger.error(msg);
cluster.fork();
}
function start(service) {
logger.init(service, VERSION);
const config = require("./config");
logger.info({
message: `GenieACS (genieacs-${service}) starting`,
pid: process.pid,
version: VERSION,
dependencies: getDependencyVersions(),
config: getConfig()
});
cluster.on("listening", function(worker, address) {
logger.info({
message: "Worker listening",
pid: worker.process.pid,
address: address.address,
port: address.port
});
});
cluster.on("exit", restartWorker);
process.on("SIGINT", function() {
logger.info({
message: "Received signal SIGINT, exiting",
pid: process.pid
});
cluster.removeListener("exit", restartWorker);
});
process.on("SIGTERM", function() {
logger.info({
message: "Received signal SIGTERM, exiting",
pid: process.pid
});
cluster.removeListener("exit", restartWorker);
for (let pid in cluster.workers)
cluster.workers[pid].kill();
});
logger.warn({
message: "This is a development branch of GenieACS. DO NOT use in production."
});
cluster.setupMaster({
exec: "lib/server",
args: [service]
});
let workerCount = config.get(`${service.toUpperCase()}_WORKER_PROCESSES`);
if (!workerCount)
workerCount = Math.max(2, require("os").cpus().length);
for (let i = 0; i < workerCount; ++ i)
cluster.fork();
}
process.on("uncaughtException", function(err) {
logger.error({
message: "Uncaught exception in master process, exiting",
exception: err
});
cluster.removeListener("exit", restartWorker);
for (let pid in cluster.workers)
cluster.workers[pid].kill();
logger.close();
});
exports.start = start;