| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require("./main.js"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var Master = module.exports; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var cluster = require("cluster"); | 
					
						
							|  |  |  | var os = require("os"); | 
					
						
							| 
									
										
										
										
											2019-10-28 01:06:43 -06:00
										 |  |  | var msgPrefix = "greenlock:"; | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | Master.create = function(opts) { | 
					
						
							|  |  |  | 	var resolveCb; | 
					
						
							| 
									
										
										
										
											2019-10-28 03:43:42 -06:00
										 |  |  | 	var _readyCb; | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 	var _kicked = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-27 03:59:49 -06:00
										 |  |  | 	var greenlock = require("./greenlock.js").create(opts); | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var ready = new Promise(function(resolve) { | 
					
						
							|  |  |  | 		resolveCb = resolve; | 
					
						
							|  |  |  | 	}).then(function(fn) { | 
					
						
							| 
									
										
										
										
											2019-10-28 03:43:42 -06:00
										 |  |  | 		_readyCb = fn; | 
					
						
							|  |  |  | 		return fn; | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function kickoff() { | 
					
						
							|  |  |  | 		if (_kicked) { | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		_kicked = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-28 01:06:43 -06:00
										 |  |  | 		Master._spawnWorkers(opts, greenlock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 		ready.then(function(fn) { | 
					
						
							|  |  |  | 			// not sure what this API should be yet
 | 
					
						
							| 
									
										
										
										
											2019-10-28 01:06:43 -06:00
										 |  |  | 			fn(); | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var master = { | 
					
						
							| 
									
										
										
										
											2019-10-28 01:06:43 -06:00
										 |  |  | 		serve: function() { | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 			kickoff(); | 
					
						
							|  |  |  | 			return master; | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		master: function(fn) { | 
					
						
							| 
									
										
										
										
											2019-10-28 03:43:42 -06:00
										 |  |  | 			if (_readyCb) { | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 				throw new Error("can't call master twice"); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			kickoff(); | 
					
						
							|  |  |  | 			resolveCb(fn); | 
					
						
							|  |  |  | 			return master; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2019-10-28 03:43:42 -06:00
										 |  |  | 	return master; | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function range(n) { | 
					
						
							| 
									
										
										
										
											2019-10-28 01:06:43 -06:00
										 |  |  | 	n = parseInt(n, 10); | 
					
						
							|  |  |  | 	if (!n) { | 
					
						
							|  |  |  | 		return []; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 	return new Array(n).join(",").split(","); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-28 01:06:43 -06:00
										 |  |  | Master._spawnWorkers = function(opts, greenlock) { | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 	var numCpus = parseInt(process.env.NUMBER_OF_PROCESSORS, 10) || os.cpus().length; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-28 01:06:43 -06:00
										 |  |  | 	// process rpc messages
 | 
					
						
							|  |  |  | 	// start when dead
 | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 	var numWorkers = parseInt(opts.numWorkers, 10); | 
					
						
							|  |  |  | 	if (!numWorkers) { | 
					
						
							|  |  |  | 		if (numCpus <= 2) { | 
					
						
							| 
									
										
										
										
											2019-10-28 03:43:42 -06:00
										 |  |  | 			numWorkers = 2; | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			numWorkers = numCpus - 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-29 06:48:31 +00:00
										 |  |  | 	cluster.once("exit", function() { | 
					
						
							| 
									
										
										
										
											2019-10-28 03:52:38 -06:00
										 |  |  | 		setTimeout(function() { | 
					
						
							|  |  |  | 			process.exit(3); | 
					
						
							|  |  |  | 		}, 100); | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-10-28 03:43:42 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var workers = range(numWorkers); | 
					
						
							|  |  |  | 	function next() { | 
					
						
							|  |  |  | 		if (!workers.length) { | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		workers.pop(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// for a nice aesthetic
 | 
					
						
							|  |  |  | 		setTimeout(function() { | 
					
						
							|  |  |  | 			Master._spawnWorker(opts, greenlock); | 
					
						
							|  |  |  | 			next(); | 
					
						
							|  |  |  | 		}, 250); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	next(); | 
					
						
							| 
									
										
										
										
											2019-10-28 01:06:43 -06:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Master._spawnWorker = function(opts, greenlock) { | 
					
						
							|  |  |  | 	var w = cluster.fork(); | 
					
						
							|  |  |  | 	// automatically added to master's `cluster.workers`
 | 
					
						
							| 
									
										
										
										
											2019-10-29 06:48:31 +00:00
										 |  |  | 	w.once("exit", function(code, signal) { | 
					
						
							| 
									
										
										
										
											2019-10-28 01:06:43 -06:00
										 |  |  | 		// TODO handle failures
 | 
					
						
							|  |  |  | 		// Should test if the first starts successfully
 | 
					
						
							|  |  |  | 		// Should exit if failures happen too quickly
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// For now just kill all when any die
 | 
					
						
							|  |  |  | 		if (signal) { | 
					
						
							|  |  |  | 			console.error("worker was killed by signal:", signal); | 
					
						
							|  |  |  | 		} else if (code !== 0) { | 
					
						
							|  |  |  | 			console.error("worker exited with error code:", code); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			console.error("worker unexpectedly quit without exit code or signal"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		process.exit(2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		//addWorker();
 | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2019-10-28 01:06:43 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	function handleMessage(msg) { | 
					
						
							|  |  |  | 		if (0 !== (msg._id || "").indexOf(msgPrefix)) { | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if ("string" !== typeof msg._funcname) { | 
					
						
							|  |  |  | 			// TODO developer error
 | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		function rpc() { | 
					
						
							|  |  |  | 			return greenlock[msg._funcname](msg._input) | 
					
						
							|  |  |  | 				.then(function(result) { | 
					
						
							|  |  |  | 					w.send({ | 
					
						
							|  |  |  | 						_id: msg._id, | 
					
						
							|  |  |  | 						_result: result | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				.catch(function(e) { | 
					
						
							|  |  |  | 					var error = new Error(e.message); | 
					
						
							|  |  |  | 					Object.getOwnPropertyNames(e).forEach(function(k) { | 
					
						
							|  |  |  | 						error[k] = e[k]; | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					w.send({ | 
					
						
							|  |  |  | 						_id: msg._id, | 
					
						
							|  |  |  | 						_error: error | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		try { | 
					
						
							|  |  |  | 			rpc(); | 
					
						
							|  |  |  | 		} catch (e) { | 
					
						
							|  |  |  | 			console.error("Unexpected and uncaught greenlock." + msg._funcname + " error:"); | 
					
						
							|  |  |  | 			console.error(e); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.on("message", handleMessage); | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | }; |