UNPKG

pot-js

Version:

Process management module

408 lines (310 loc) 12.1 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _events = require('events'); var _potLogger = require('pot-logger'); var _chalk = require('chalk'); var _chalk2 = _interopRequireDefault(_chalk); var _delay = require('delay'); var _delay2 = _interopRequireDefault(_delay); var _Connection = require('../Connection'); var _Connection2 = _interopRequireDefault(_Connection); var _WorkerMonitor = require('./WorkerMonitor'); var _WorkerMonitor2 = _interopRequireDefault(_WorkerMonitor); var _workspace = require('../utils/workspace'); var _workspace2 = _interopRequireDefault(_workspace); var _watch = require('../utils/watch'); var _watch2 = _interopRequireDefault(_watch); var _onSignalExit = require('../utils/onSignalExit'); var _onSignalExit2 = _interopRequireDefault(_onSignalExit); var _createScriptRunner = require('../utils/createScriptRunner'); var _createScriptRunner2 = _interopRequireDefault(_createScriptRunner); var _EnvVar = require('../utils/EnvVar'); var _getKey = require('../utils/getKey'); var _getKey2 = _interopRequireDefault(_getKey); var _Errors = require('../utils/Errors'); var _Errors2 = _interopRequireDefault(_Errors); var _ensureInstanceNumber = require('../utils/ensureInstanceNumber'); var _ensureInstanceNumber2 = _interopRequireDefault(_ensureInstanceNumber); var _PidHelpers = require('../utils/PidHelpers'); var _SocketsHelpers = require('../utils/SocketsHelpers'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } class MasterMonitor extends _events.EventEmitter { constructor(options) { var _this; _this = super(); this.currentWorkerMonitor = null; const space = options.workspace, logsDir = options.logsDir, execPath = options.execPath, spawnArgs = options.spawnArgs, daemon = options.daemon, env = options.env, monitorProcessTitle = options.monitorProcessTitle, cwd = options.baseDir, production = options.production, name = options.name, events = options.events, watchOptions = options.watch, respawnOptions = _objectWithoutProperties(options, ['workspace', 'logsDir', 'execPath', 'spawnArgs', 'daemon', 'env', 'monitorProcessTitle', 'baseDir', 'production', 'name', 'events', 'watch']); (0, _potLogger.setLoggers)(_extends({}, options, { enable: !daemon || logsDir, logsDir: logsDir || '.logs' })); _workspace2.default.set(space); process.title = monitorProcessTitle; this._workerMonitorOptions = _extends({ stdio: 'pipe' }, respawnOptions, { execPath, execArgv: spawnArgs, data: options, env: function () { const res = _extends({}, env); if (!res.NODE_ENV) { res.NODE_ENV = production ? 'production' : 'development'; } res[_EnvVar.ENV_VAR_KEY] = JSON.stringify(options); return res; }() }); const eventsLogger = (0, _potLogger.ensureLogger)('events', 'gray'); const runScript = (0, _createScriptRunner2.default)({ cwd, logger: eventsLogger }); this._runEvent = function (event) { for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } const hook = events[event]; if (hook) { const prefix = [event].concat(args).filter(Boolean).join(' '); eventsLogger.info(_chalk2.default.gray(`${prefix} - ${hook}`)); runScript(event, ...args); } }; this.workerMonitors = []; const exit = (() => { var _ref = _asyncToGenerator(function* () { _potLogger.logger.debug('exit'); try { const connection = yield _Connection2.default.getByName(name); if (connection) { yield connection.requestStopServer(); } yield Promise.all(_this.workerMonitors.map((() => { var _ref2 = _asyncToGenerator(function* (monitor) { return monitor.stop(); }); return function (_x) { return _ref2.apply(this, arguments); }; })())); } catch (err) { _potLogger.logger.debug(err); } process.exit(); }); return function exit() { return _ref.apply(this, arguments); }; })(); process.on('uncaughtException', (() => { var _ref3 = _asyncToGenerator(function* (err) { _potLogger.logger.fatal(err); yield exit(); }); return function (_x2) { return _ref3.apply(this, arguments); }; })()); (0, _onSignalExit2.default)(_asyncToGenerator(function* () { (0, _potLogger.setLoggers)('logLevel', 'OFF'); yield exit(); })); (0, _watch2.default)(_extends({ cwd }, watchOptions), _asyncToGenerator(function* () { _potLogger.logger.trace('watch:restart'); process.emit('watch:restart'); const length = _this.workerMonitors.length; const reloadDelay = length > 1 ? 2000 / length : 0; for (const workerMonitor of _this.workerMonitors) { yield workerMonitor.restart(); yield (0, _delay2.default)(reloadDelay); } })); } // will be set by server socket spawn() { var _arguments = arguments, _this2 = this; return _asyncToGenerator(function* () { let options = _arguments.length > 0 && _arguments[0] !== undefined ? _arguments[0] : {}; const newInstances = (0, _ensureInstanceNumber2.default)(options.instances); const EventTypes = _WorkerMonitor2.default.EventTypes; const runEvent = _this2._runEvent; const workerMonitors = new Array(newInstances).fill().map(function () { return new _WorkerMonitor2.default(_this2._workerMonitorOptions); }); const errors = new _Errors2.default(); const bootstraps = workerMonitors.map(function (workerMonitor) { let displayName = workerMonitor.data.name; workerMonitor.on(EventTypes.STOP, function () { _potLogger.logger.warn(`"${displayName}" stopped`); runEvent(EventTypes.STOP); }); workerMonitor.on(EventTypes.CRASH, function () { _potLogger.logger.fatal(`"${displayName}" crashed`); runEvent(EventTypes.CRASH); }); workerMonitor.on(EventTypes.SLEEP, function () { _potLogger.logger.warn(`"${displayName}" sleeped`); runEvent(EventTypes.SLEEP); }); workerMonitor.on(EventTypes.SPAWN, function () { runEvent(EventTypes.SPAWN); }); workerMonitor.on(EventTypes.EXIT, (() => { var _ref6 = _asyncToGenerator(function* (code, signal) { _potLogger.logger.debug(`"${displayName}" exit with code "${code}", signal "${signal}"`); runEvent(EventTypes.EXIT, code, signal); }); return function (_x4, _x5) { return _ref6.apply(this, arguments); }; })()); workerMonitor.on(EventTypes.STDOUT, function (data) { runEvent(EventTypes.STDOUT); _potLogger.logger.info(data.toString().trim()); }); workerMonitor.on(EventTypes.STDERR, function (data) { runEvent(EventTypes.STDERR); _potLogger.logger.error(data.toString().trim()); }); workerMonitor.on(EventTypes.WARN, function (data) { runEvent(EventTypes.WARN); _potLogger.logger.warn(data.toString().trim()); }); workerMonitor.on(EventTypes.RESTART, _asyncToGenerator(function* () { yield (0, _PidHelpers.writePid)(workerMonitor.data); _potLogger.logger.info(`"${displayName}" restarted`); runEvent(EventTypes.RESTART); })); return new Promise(function (resolve) { workerMonitor.on(EventTypes.START, _asyncToGenerator(function* () { try { const workerMonitors = _this2.workerMonitors; const numbers = workerMonitors.length ? workerMonitors.map(function (wm) { return wm.id; }) : [0]; workerMonitor.id = Math.max(...numbers) + 1; workerMonitors.push(workerMonitor); const options = workerMonitor.data, id = workerMonitor.id; _workspace2.default.set(options); const key = (0, _getKey2.default)(workerMonitor); const pidFile = yield (0, _PidHelpers.getPidFile)(key); const socketPath = yield (0, _SocketsHelpers.getSocketPath)(key); options.instanceId = id; options.key = key; options.pidFile = pidFile; options.socketPath = socketPath; options.displayName = options.name + (id ? ` #${id}` : ''); yield (0, _SocketsHelpers.startServer)(_this2, workerMonitor); yield (0, _PidHelpers.writePid)(options); workerMonitors.sort(function (a, b) { return a.id - b.id; }); displayName = workerMonitor.data.displayName; _potLogger.logger.info(`"${displayName}" started`); runEvent(EventTypes.START); } catch (err) { _potLogger.logger.debug(err); errors.push(err); } resolve(workerMonitor.toJSON()); })); workerMonitor.start(); }); }); const added = yield Promise.all(bootstraps); const ok = bootstraps.length > errors.length; return { ok, errors: errors.toJSON(), added }; })(); } scale(number) { var _this3 = this; return _asyncToGenerator(function* () { const delta = (0, _ensureInstanceNumber2.default)(number) - _this3.workerMonitors.length; if (!delta) { return { ok: true, errors: [] }; } else if (delta > 0) { return _this3.spawn({ instances: delta }); } else { const workerMonitors = _this3.workerMonitors; const toRemove = workerMonitors.slice(workerMonitors.length + delta); const errors = new _Errors2.default(); const removed = yield Promise.all(toRemove.map((() => { var _ref9 = _asyncToGenerator(function* (workerMonitor) { const state = workerMonitor.toJSON(); yield _this3.requestShutDown(workerMonitor).catch(function (err) { return errors.push(err); }); return state; }); return function (_x6) { return _ref9.apply(this, arguments); }; })())); return { ok: !errors.length, errors: errors.toJSON(), removed }; } })(); } state(newState) { var _this4 = this; return _asyncToGenerator(function* () { const currentWorkerMonitor = _this4.currentWorkerMonitor; if (currentWorkerMonitor) { if (newState) { Object.assign(currentWorkerMonitor.data, newState); } return currentWorkerMonitor.toJSON(); } })(); } restart() { var _this5 = this; return _asyncToGenerator(function* () { const currentWorkerMonitor = _this5.currentWorkerMonitor; if (currentWorkerMonitor) { yield currentWorkerMonitor.restart(); return true; } return false; })(); } requestShutDown(workerMonitor) { var _this6 = this; return _asyncToGenerator(function* () { yield workerMonitor.stop(); var _workerMonitor$toJSON = workerMonitor.toJSON(); const socketPath = _workerMonitor$toJSON.socketPath, pidFile = _workerMonitor$toJSON.pidFile; const workerMonitors = _this6.workerMonitors; const index = workerMonitors.indexOf(workerMonitor); workerMonitors.splice(index, 1); yield Promise.all([(0, _SocketsHelpers.removeDomainSocketFile)(socketPath), (0, _PidHelpers.removePidFile)(pidFile)]); if (!workerMonitors.length) process.exit(0); })(); } } exports.default = MasterMonitor;