| 
									
										
										
										
											2014-02-27 10:06:31 -05:00
										 |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var	nconf = require('nconf'), | 
					
						
							|  |  |  | 	fs = require('fs'), | 
					
						
							| 
									
										
										
										
											2014-09-16 11:08:25 -04:00
										 |  |  | 	path = require('path'), | 
					
						
							| 
									
										
										
										
											2014-09-03 01:24:26 -04:00
										 |  |  | 	cluster = require('cluster'), | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 	async = require('async'), | 
					
						
							| 
									
										
										
										
											2014-09-30 21:48:39 -04:00
										 |  |  | 	logrotate = require('logrotate-stream'), | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	pkg = require('./package.json'), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-04 17:48:22 -04:00
										 |  |  | 	pidFilePath = __dirname + '/pidfile', | 
					
						
							| 
									
										
										
										
											2014-09-30 21:48:39 -04:00
										 |  |  | 	output = logrotate({ file: __dirname + '/logs/output.log', size: '1m', keep: 3, compress: true }), | 
					
						
							|  |  |  | 	silent = process.env.NODE_ENV !== 'development' ? true : false, | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | 	numProcs, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-05 13:23:26 -04:00
										 |  |  | 	Loader = { | 
					
						
							|  |  |  | 		timesStarted: 0, | 
					
						
							|  |  |  | 		shutdown_queue: [], | 
					
						
							|  |  |  | 		js: { | 
					
						
							|  |  |  | 			cache: undefined, | 
					
						
							|  |  |  | 			map: undefined | 
					
						
							| 
									
										
										
										
											2014-09-29 19:31:27 -04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		css: { | 
					
						
							|  |  |  | 			cache: undefined, | 
					
						
							|  |  |  | 			acpCache: undefined | 
					
						
							| 
									
										
										
										
											2014-09-05 13:23:26 -04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2014-02-27 10:06:31 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | Loader.init = function(callback) { | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 	cluster.setupMaster({ | 
					
						
							|  |  |  | 		exec: "app.js", | 
					
						
							| 
									
										
										
										
											2014-09-30 21:48:39 -04:00
										 |  |  | 		silent: silent | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2014-10-03 01:09:35 -04:00
										 |  |  | 	Loader.primaryWorker = 1; | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-30 21:48:39 -04:00
										 |  |  | 	if (silent) { | 
					
						
							|  |  |  | 		console.log = function(value) { | 
					
						
							|  |  |  | 			output.write(value + '\n'); | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | 	process.on('SIGHUP', Loader.restart); | 
					
						
							|  |  |  | 	callback(); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Loader.displayStartupMessages = function(callback) { | 
					
						
							|  |  |  | 	console.log('NodeBB v' + pkg.version + ' Copyright (C) 2013-2014 NodeBB Inc.'); | 
					
						
							|  |  |  | 	console.log('This program comes with ABSOLUTELY NO WARRANTY.'); | 
					
						
							|  |  |  | 	console.log('This is free software, and you are welcome to redistribute it under certain conditions.'); | 
					
						
							|  |  |  | 	console.log('For the full license, please visit: http://www.gnu.org/copyleft/gpl.html'); | 
					
						
							|  |  |  | 	console.log(''); | 
					
						
							|  |  |  | 	callback(); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Loader.addClusterEvents = function(callback) { | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 	cluster.on('fork', function(worker) { | 
					
						
							|  |  |  | 		worker.on('message', function(message) { | 
					
						
							|  |  |  | 			if (message && typeof message === 'object' && message.action) { | 
					
						
							| 
									
										
										
										
											2014-10-08 12:07:33 -04:00
										 |  |  | 				var otherWorkers; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 				switch (message.action) { | 
					
						
							|  |  |  | 					case 'ready': | 
					
						
							| 
									
										
										
										
											2014-09-05 13:23:26 -04:00
										 |  |  | 						if (Loader.js.cache) { | 
					
						
							|  |  |  | 							worker.send({ | 
					
						
							|  |  |  | 								action: 'js-propagate', | 
					
						
							|  |  |  | 								cache: Loader.js.cache, | 
					
						
							|  |  |  | 								map: Loader.js.map | 
					
						
							|  |  |  | 							}); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-29 19:31:27 -04:00
										 |  |  | 						if (Loader.css.cache) { | 
					
						
							|  |  |  | 							worker.send({ | 
					
						
							|  |  |  | 								action: 'css-propagate', | 
					
						
							|  |  |  | 								cache: Loader.css.cache, | 
					
						
							|  |  |  | 								acpCache: Loader.css.acpCache | 
					
						
							|  |  |  | 							}); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-04 17:09:57 -04:00
										 |  |  | 						// Kill an instance in the shutdown queue
 | 
					
						
							|  |  |  | 						var workerToKill = Loader.shutdown_queue.pop(); | 
					
						
							|  |  |  | 						if (workerToKill) { | 
					
						
							|  |  |  | 							cluster.workers[workerToKill].kill(); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 					case 'restart': | 
					
						
							|  |  |  | 						console.log('[cluster] Restarting...'); | 
					
						
							|  |  |  | 						Loader.restart(function(err) { | 
					
						
							|  |  |  | 							console.log('[cluster] Restarting...'); | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2014-09-04 17:09:57 -04:00
										 |  |  | 					case 'reload': | 
					
						
							|  |  |  | 						console.log('[cluster] Reloading...'); | 
					
						
							|  |  |  | 						Loader.reload(); | 
					
						
							|  |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2014-09-04 17:39:53 -04:00
										 |  |  | 					case 'js-propagate': | 
					
						
							| 
									
										
										
										
											2014-09-05 13:23:26 -04:00
										 |  |  | 						Loader.js.cache = message.cache; | 
					
						
							|  |  |  | 						Loader.js.map = message.map; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-08 12:07:33 -04:00
										 |  |  | 						otherWorkers = Object.keys(cluster.workers).filter(function(worker_id) { | 
					
						
							|  |  |  | 							return parseInt(worker_id, 10) !== parseInt(worker.id, 10); | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-04 17:39:53 -04:00
										 |  |  | 						otherWorkers.forEach(function(worker_id) { | 
					
						
							|  |  |  | 							cluster.workers[worker_id].send({ | 
					
						
							|  |  |  | 								action: 'js-propagate', | 
					
						
							|  |  |  | 								cache: message.cache, | 
					
						
							|  |  |  | 								map: message.map | 
					
						
							|  |  |  | 							}); | 
					
						
							|  |  |  | 						}); | 
					
						
							| 
									
										
										
										
											2014-09-04 17:43:44 -04:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2014-09-29 19:31:27 -04:00
										 |  |  | 					case 'css-propagate': | 
					
						
							|  |  |  | 						Loader.css.cache = message.cache; | 
					
						
							|  |  |  | 						Loader.css.acpCache = message.acpCache; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-08 12:07:33 -04:00
										 |  |  | 						otherWorkers = Object.keys(cluster.workers).filter(function(worker_id) { | 
					
						
							|  |  |  | 							return parseInt(worker_id, 10) !== parseInt(worker.id, 10); | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-29 19:31:27 -04:00
										 |  |  | 						otherWorkers.forEach(function(worker_id) { | 
					
						
							|  |  |  | 							cluster.workers[worker_id].send({ | 
					
						
							|  |  |  | 								action: 'css-propagate', | 
					
						
							|  |  |  | 								cache: message.cache, | 
					
						
							|  |  |  | 								acpCache: message.acpCache | 
					
						
							|  |  |  | 							}); | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2014-09-05 13:44:56 -04:00
										 |  |  | 					case 'listening': | 
					
						
							|  |  |  | 						if (message.primary) { | 
					
						
							|  |  |  | 							Loader.primaryWorker = parseInt(worker.id, 10); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2014-09-04 17:41:00 -04:00
										 |  |  | 					case 'user:connect': | 
					
						
							|  |  |  | 					case 'user:disconnect': | 
					
						
							| 
									
										
										
										
											2014-09-29 16:35:13 -04:00
										 |  |  | 					case 'config:update': | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | 						Loader.notifyWorkers(message); | 
					
						
							| 
									
										
										
										
											2014-09-04 17:41:00 -04:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2014-09-03 01:24:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-05 13:23:26 -04:00
										 |  |  | 	cluster.on('listening', function(worker) { | 
					
						
							|  |  |  | 		console.log('[cluster] Child Process (' + worker.process.pid + ') listening for connections.'); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 	cluster.on('exit', function(worker, code, signal) { | 
					
						
							|  |  |  | 		if (code !== 0) { | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | 			if (Loader.timesStarted < numProcs*3) { | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 				Loader.timesStarted++; | 
					
						
							| 
									
										
										
										
											2014-09-04 00:01:08 -04:00
										 |  |  | 				if (Loader.crashTimer) { | 
					
						
							|  |  |  | 					clearTimeout(Loader.crashTimer); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				Loader.crashTimer = setTimeout(function() { | 
					
						
							|  |  |  | 					Loader.timesStarted = 0; | 
					
						
							|  |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | 				console.log(numProcs*3 + ' restarts in 10 seconds, most likely an error on startup. Halting.'); | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 				process.exit(); | 
					
						
							| 
									
										
										
										
											2014-09-03 01:24:26 -04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		console.log('[cluster] Child Process (' + worker.process.pid + ') has exited (code: ' + code + ')'); | 
					
						
							| 
									
										
										
										
											2014-09-04 17:09:57 -04:00
										 |  |  | 		if (!worker.suicide) { | 
					
						
							| 
									
										
										
										
											2014-10-08 12:07:33 -04:00
										 |  |  | 			console.log('[cluster] Spinning up another process...'); | 
					
						
							| 
									
										
										
										
											2014-09-05 13:44:56 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			var wasPrimary = parseInt(worker.id, 10) === Loader.primaryWorker; | 
					
						
							|  |  |  | 			cluster.fork({ | 
					
						
							|  |  |  | 				handle_jobs: wasPrimary | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2014-09-04 17:09:57 -04:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-05-04 16:46:09 -04:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2014-09-04 00:56:50 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | 	callback(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | Loader.start = function(callback) { | 
					
						
							| 
									
										
										
										
											2014-10-03 01:09:35 -04:00
										 |  |  | 	var output = logrotate({ file: __dirname + '/logs/output.log', size: '1m', keep: 3, compress: true }), | 
					
						
							|  |  |  | 		worker; | 
					
						
							| 
									
										
										
										
											2014-09-05 13:44:56 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | 	console.log('Clustering enabled: Spinning up ' + numProcs + ' process(es).\n'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(var x=0;x<numProcs;x++) { | 
					
						
							| 
									
										
										
										
											2014-09-04 17:09:57 -04:00
										 |  |  | 		// Only the first worker sets up templates/sounds/jobs/etc
 | 
					
						
							| 
									
										
										
										
											2014-09-30 21:48:39 -04:00
										 |  |  | 		worker = cluster.fork({ | 
					
						
							| 
									
										
										
										
											2014-09-05 13:44:56 -04:00
										 |  |  | 			cluster_setup: x === 0, | 
					
						
							| 
									
										
										
										
											2014-09-30 21:48:39 -04:00
										 |  |  | 			handle_jobs: x === 0 | 
					
						
							| 
									
										
										
										
											2014-09-05 13:44:56 -04:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2014-09-30 21:48:39 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Logging
 | 
					
						
							|  |  |  | 		if (silent) { | 
					
						
							|  |  |  | 			worker.process.stdout.pipe(output); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-09-04 17:09:57 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	callback(); | 
					
						
							| 
									
										
										
										
											2014-10-08 12:07:33 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | Loader.restart = function(callback) { | 
					
						
							| 
									
										
										
										
											2014-09-04 17:09:57 -04:00
										 |  |  | 	// Slate existing workers for termination -- welcome to death row.
 | 
					
						
							|  |  |  | 	Loader.shutdown_queue = Loader.shutdown_queue.concat(Object.keys(cluster.workers)); | 
					
						
							|  |  |  | 	Loader.start(); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Loader.reload = function() { | 
					
						
							|  |  |  | 	Object.keys(cluster.workers).forEach(function(worker_id) { | 
					
						
							| 
									
										
										
										
											2014-09-04 17:39:53 -04:00
										 |  |  | 		cluster.workers[worker_id].send({ | 
					
						
							|  |  |  | 			action: 'reload' | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2014-09-04 17:09:57 -04:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2014-09-04 17:41:00 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2014-09-03 15:23:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | Loader.notifyWorkers = function (msg) { | 
					
						
							|  |  |  | 	Object.keys(cluster.workers).forEach(function(id) { | 
					
						
							|  |  |  | 		cluster.workers[id].send(msg); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-09-16 11:17:57 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | nconf.argv().file({ | 
					
						
							|  |  |  | 	file: path.join(__dirname, '/config.json') | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | numProcs = nconf.get('cluster') || 1; | 
					
						
							|  |  |  | numProcs = (numProcs === true) ? require('os').cpus().length : numProcs; | 
					
						
							| 
									
										
										
										
											2014-09-16 11:17:57 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-04 17:48:22 -04:00
										 |  |  | if (nconf.get('daemon') !== false) { | 
					
						
							|  |  |  | 	if (fs.existsSync(pidFilePath)) { | 
					
						
							|  |  |  | 		try { | 
					
						
							|  |  |  | 			var	pid = fs.readFileSync(pidFilePath, { encoding: 'utf-8' }); | 
					
						
							|  |  |  | 			process.kill(pid, 0); | 
					
						
							|  |  |  | 			process.exit(); | 
					
						
							|  |  |  | 		} catch (e) { | 
					
						
							|  |  |  | 			fs.unlinkSync(pidFilePath); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-30 21:48:39 -04:00
										 |  |  | 	require('daemon')(); | 
					
						
							| 
									
										
										
										
											2014-09-04 17:48:22 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	fs.writeFile(__dirname + '/pidfile', process.pid); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-13 13:03:06 -04:00
										 |  |  | async.series([ | 
					
						
							|  |  |  | 	Loader.init, | 
					
						
							|  |  |  | 	Loader.displayStartupMessages, | 
					
						
							|  |  |  | 	Loader.addClusterEvents, | 
					
						
							|  |  |  | 	Loader.start | 
					
						
							|  |  |  | ], function(err) { | 
					
						
							|  |  |  | 	if (err) { | 
					
						
							|  |  |  | 		console.log('[loader] Error during startup: ' + err.message); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }); |