diff --git a/app.js b/app.js index 446b0f7c42..1db84c307a 100644 --- a/app.js +++ b/app.js @@ -30,7 +30,6 @@ var fs = require('fs'), semver = require('semver'), winston = require('winston'), path = require('path'), - cluster = require('cluster'), pkg = require('./package.json'), utils = require('./public/src/utils.js'); @@ -60,7 +59,7 @@ if(os.platform() === 'linux') { }); } -if (!cluster.isWorker) { +if (!process.send) { // If run using `node app`, log GNU copyright info along with server info winston.info('NodeBB v' + pkg.version + ' Copyright (C) 2013-2014 NodeBB Inc.'); winston.info('This program comes with ABSOLUTELY NO WARRANTY.'); @@ -98,6 +97,11 @@ function loadConfig() { views_dir: path.join(__dirname, 'public/templates') }); + if (!nconf.get('isCluster')) { + nconf.set('isPrimary', 'true'); + nconf.set('isCluster', 'false'); + } + // Ensure themes_path is a full filepath nconf.set('themes_path', path.resolve(__dirname, nconf.get('themes_path'))); nconf.set('core_templates_path', path.join(__dirname, 'src/views')); @@ -119,13 +123,11 @@ function start() { nconf.set('port', urlObject.port || nconf.get('port') || nconf.get('PORT') || 4567); nconf.set('upload_url', relativePath + '/uploads/'); - if (!cluster.isWorker || process.env.cluster_setup === 'true') { + if (nconf.get('isPrimary') === 'true') { winston.info('Time: %s', (new Date()).toString()); winston.info('Initializing NodeBB v%s', pkg.version); winston.verbose('* using configuration stored in: %s', configFile); - } - if (cluster.isWorker && process.env.cluster_setup === 'true') { var host = nconf.get(nconf.get('database') + ':host'), storeLocation = host ? 'at ' + host + (host.indexOf('/') === -1 ? ':' + nconf.get(nconf.get('database') + ':port') : '') : ''; @@ -157,7 +159,7 @@ function start() { webserver.init(); sockets.init(webserver.server); - if (cluster.isWorker && process.env.handle_jobs === 'true') { + if (nconf.get('isPrimary')) { require('./src/notifications').init(); require('./src/user').startJobs(); } @@ -191,13 +193,13 @@ function start() { meta.js.cache = message.cache; meta.js.map = message.map; meta.js.hash = message.hash; - winston.verbose('[cluster] Client-side javascript and mapping propagated to worker %s', cluster.worker.id); + winston.verbose('[cluster] Client-side javascript and mapping propagated to worker %s', process.pid); break; case 'css-propagate': meta.css.cache = message.cache; meta.css.acpCache = message.acpCache; meta.css.hash = message.hash; - winston.verbose('[cluster] Stylesheets propagated to worker %s', cluster.worker.id); + winston.verbose('[cluster] Stylesheets propagated to worker %s', process.pid); break; } }); @@ -212,11 +214,7 @@ function start() { } else { winston.warn('Your NodeBB schema is out-of-date. Please run the following command to bring your dataset up to spec:'); winston.warn(' ./nodebb upgrade'); - if (cluster.isWorker) { - cluster.worker.kill(); - } else { - process.exit(); - } + process.exit(); } }); }); diff --git a/loader.js b/loader.js index 8c8ad20491..a788a0ca26 100644 --- a/loader.js +++ b/loader.js @@ -5,7 +5,8 @@ var nconf = require('nconf'), fs = require('fs'), url = require('url'), path = require('path'), - cluster = require('cluster'), + fork = require('child_process').fork, + async = require('async'), logrotate = require('logrotate-stream'), @@ -15,9 +16,8 @@ var nconf = require('nconf'), output = logrotate({ file: __dirname + '/logs/output.log', size: '1m', keep: 3, compress: true }), silent = process.env.NODE_ENV !== 'development', numProcs, - handles = {}, - handleIndex = 0, - server, + + workers = [], Loader = { timesStarted: 0, @@ -32,11 +32,6 @@ var nconf = require('nconf'), }; Loader.init = function(callback) { - cluster.setupMaster({ - exec: "app.js", - silent: silent - }); - Loader.primaryWorker = 1; if (silent) { console.log = function(value) { @@ -60,84 +55,9 @@ Loader.displayStartupMessages = function(callback) { callback(); }; -Loader.addClusterEvents = function(callback) { - cluster.on('fork', function(worker) { - worker.on('message', function(message) { - if (message && typeof message === 'object' && message.action) { - var otherWorkers; - - switch (message.action) { - case 'ready': - if (Loader.js.cache) { - worker.send({ - action: 'js-propagate', - cache: Loader.js.cache, - map: Loader.js.map, - hash: Loader.js.hash - }); - } - - if (Loader.css.cache) { - worker.send({ - action: 'css-propagate', - cache: Loader.css.cache, - acpCache: Loader.css.acpCache, - hash: Loader.css.hash - }); - } - break; - case 'restart': - console.log('[cluster] Restarting...'); - Loader.restart(function(err) { - console.log('[cluster] Restarting...'); - }); - break; - case 'reload': - console.log('[cluster] Reloading...'); - Loader.reload(); - break; - case 'js-propagate': - Loader.js.cache = message.cache; - Loader.js.map = message.map; - Loader.js.hash = message.hash; - - Loader.notifyWorkers({ - action: 'js-propagate', - cache: message.cache, - map: message.map, - hash: message.hash - }, worker.id); - break; - case 'css-propagate': - Loader.css.cache = message.cache; - Loader.css.acpCache = message.acpCache; - Loader.css.hash = message.hash; - - Loader.notifyWorkers({ - action: 'css-propagate', - cache: message.cache, - acpCache: message.acpCache, - hash: message.hash - }, worker.id); - break; - case 'listening': - if (message.primary) { - Loader.primaryWorker = parseInt(worker.id, 10); - } - break; - case 'config:update': - Loader.notifyWorkers(message); - break; - } - } - }); - }); +Loader.addWorkerEvents = function(worker) { - cluster.on('listening', function(worker) { - console.log('[cluster] Child Process (' + worker.process.pid + ') listening for connections.'); - }); - - cluster.on('exit', function(worker, code, signal) { + worker.on('exit', function(code, signal) { if (code !== 0) { if (Loader.timesStarted < numProcs*3) { Loader.timesStarted++; @@ -153,118 +73,134 @@ Loader.addClusterEvents = function(callback) { } } - console.log('[cluster] Child Process (' + worker.process.pid + ') has exited (code: ' + code + ', signal: ' + signal +')'); + console.log('[cluster] Child Process (' + worker.pid + ') has exited (code: ' + code + ', signal: ' + signal +')'); if (!worker.suicide) { - console.log('[cluster] Spinning up another process...'); + console.log('[cluster] Spinning up another process...'); - var wasPrimary = parseInt(worker.id, 10) === Loader.primaryWorker; - forkWorker(wasPrimary); + forkWorker(worker.index, worker.isPrimary); } }); - cluster.on('disconnect', function(worker) { - console.log('[cluster] Child Process (' + worker.process.pid + ') has disconnected'); - }); + worker.on('message', function(message) { + if (message && typeof message === 'object' && message.action) { + var otherWorkers; - callback(); + switch (message.action) { + case 'ready': + if (Loader.js.cache) { + worker.send({ + action: 'js-propagate', + cache: Loader.js.cache, + map: Loader.js.map, + hash: Loader.js.hash + }); + } + + if (Loader.css.cache) { + worker.send({ + action: 'css-propagate', + cache: Loader.css.cache, + acpCache: Loader.css.acpCache, + hash: Loader.css.hash + }); + } + break; + case 'restart': + console.log('[cluster] Restarting...'); + Loader.restart(function(err) { + console.log('[cluster] Restarting...'); + }); + break; + case 'reload': + console.log('[cluster] Reloading...'); + Loader.reload(); + break; + case 'js-propagate': + Loader.js.cache = message.cache; + Loader.js.map = message.map; + Loader.js.hash = message.hash; + + Loader.notifyWorkers({ + action: 'js-propagate', + cache: message.cache, + map: message.map, + hash: message.hash + }, worker.pid); + break; + case 'css-propagate': + Loader.css.cache = message.cache; + Loader.css.acpCache = message.acpCache; + Loader.css.hash = message.hash; + + Loader.notifyWorkers({ + action: 'css-propagate', + cache: message.cache, + acpCache: message.acpCache, + hash: message.hash + }, worker.pid); + break; + case 'listening': + if (message.primary) { + Loader.primaryWorker = parseInt(worker.pid, 10); + } + break; + case 'config:update': + Loader.notifyWorkers(message); + break; + } + } + }); }; Loader.start = function(callback) { console.log('Clustering enabled: Spinning up ' + numProcs + ' process(es).\n'); - for(var x=0; x