| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2019-11-01 15:14:07 -06:00
										 |  |  |     var resolveCb; | 
					
						
							|  |  |  |     var _readyCb; | 
					
						
							|  |  |  |     var _kicked = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var greenlock = require("./greenlock.js").create(opts); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var ready = new Promise(function(resolve) { | 
					
						
							|  |  |  |         resolveCb = resolve; | 
					
						
							|  |  |  |     }).then(function(fn) { | 
					
						
							|  |  |  |         _readyCb = fn; | 
					
						
							|  |  |  |         return fn; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function kickoff() { | 
					
						
							|  |  |  |         if (_kicked) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         _kicked = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Master._spawnWorkers(opts, greenlock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ready.then(function(fn) { | 
					
						
							|  |  |  |             // not sure what this API should be yet
 | 
					
						
							|  |  |  |             fn(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var master = { | 
					
						
							|  |  |  |         serve: function() { | 
					
						
							|  |  |  |             kickoff(); | 
					
						
							|  |  |  |             return master; | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         master: function(fn) { | 
					
						
							|  |  |  |             if (_readyCb) { | 
					
						
							|  |  |  |                 throw new Error("can't call master twice"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             kickoff(); | 
					
						
							|  |  |  |             resolveCb(fn); | 
					
						
							|  |  |  |             return master; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     return master; | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function range(n) { | 
					
						
							| 
									
										
										
										
											2019-11-01 15:14:07 -06:00
										 |  |  |     n = parseInt(n, 10); | 
					
						
							|  |  |  |     if (!n) { | 
					
						
							|  |  |  |         return []; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return new Array(n).join(",").split(","); | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-28 01:06:43 -06:00
										 |  |  | Master._spawnWorkers = function(opts, greenlock) { | 
					
						
							| 
									
										
										
										
											2019-11-01 15:14:07 -06:00
										 |  |  |     var numCpus = parseInt(process.env.NUMBER_OF_PROCESSORS, 10) || os.cpus().length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // process rpc messages
 | 
					
						
							|  |  |  |     // start when dead
 | 
					
						
							|  |  |  |     var numWorkers = parseInt(opts.workers || opts.numWorkers, 10); | 
					
						
							|  |  |  |     if (!numWorkers) { | 
					
						
							|  |  |  |         if (numCpus <= 2) { | 
					
						
							|  |  |  |             numWorkers = 2; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             numWorkers = numCpus - 1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cluster.once("exit", function() { | 
					
						
							|  |  |  |         setTimeout(function() { | 
					
						
							|  |  |  |             process.exit(3); | 
					
						
							|  |  |  |         }, 100); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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) { | 
					
						
							| 
									
										
										
										
											2019-11-01 15:14:07 -06:00
										 |  |  |     var w = cluster.fork(); | 
					
						
							|  |  |  |     // automatically added to master's `cluster.workers`
 | 
					
						
							|  |  |  |     w.once("exit", function(code, signal) { | 
					
						
							|  |  |  |         // 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();
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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
										 |  |  | }; |