UNPKG

pandora

Version:

A powerful and lightweight application manager for Node.js applications powered by TypeScript.

172 lines (145 loc) 4.84 kB
'use strict'; require('source-map-support').install(); import program = require('commander'); import {PROCESS_ERROR, FINISH_SHUTDOWN, PROCESS_READY, SHUTDOWN, PANDORA_PROCESS} from '../const'; import {ProcessRepresentation} from '../domain'; import assert = require('assert'); import {makeRequire} from 'pandora-dollar'; import {ScalableMaster} from './ScalableMaster'; import {SpawnWrapperUtils} from './SpawnWrapperUtils'; import {consoleLogger} from 'pandora-dollar'; import {CoreSDK} from 'pandora-core-sdk'; import {CoreSDKWithExtendedConfig} from '../util/CoreSDKWithExtendedConfig'; /** * class ProcessBootstrap * Bootstrap a worker process, handing all phases of an application stating */ export class ProcessBootstrap { public master: ScalableMaster; public processRepresentation: ProcessRepresentation; protected coreSdk: CoreSDK; constructor(processRepresentation: ProcessRepresentation) { this.processRepresentation = processRepresentation; if(this.processRepresentation.scale > 1) { this.master = new ScalableMaster(processRepresentation); return; } else { const {appName, appDir} = this.processRepresentation; this.coreSdk = new CoreSDKWithExtendedConfig({ mode: 'worker', appName, appDir }); } } async start() { if(this.master) { await this.startAsMaster(); return; } await this.startAsWorker(); } async stop() { if(this.master) { await this.master.stop(); return; } try { await this.coreSdk.stop(); } catch(err) { // ignore } SpawnWrapperUtils.unwrap(); } async startAsMaster() { await this.master.start(); } async startAsWorker() { SpawnWrapperUtils.setAsFirstLevel(); SpawnWrapperUtils.wrap(); process.env[PANDORA_PROCESS] = JSON.stringify(this.processRepresentation); await this.coreSdk.start(); // Require the entryFile if there given it, pandora.fork() dep on it if(this.processRepresentation.entryFile) { const entryFileBaseDir = this.processRepresentation.entryFileBaseDir; const ownRequire = entryFileBaseDir ? makeRequire(entryFileBaseDir) : require; ownRequire(this.processRepresentation.entryFile); } } /** * A static method to handing the CLI */ static cmd() { program .allowUnknownOption() .option('--params [params]') .parse(process.argv); let options; try { options = JSON.parse(program.params); assert(options.appName, 'The field appName required by ProcessBootstrap'); assert(options.appDir, 'The field appDir required by ProcessBootstrap'); assert(options.processName, 'The field processName required by ProcessBootstrap'); } catch (err) { err.message = `Invalid options "${program.params}", ${err.message}`; consoleLogger.error(err); if (process.send) { process.send({action: PROCESS_ERROR, error: err}); } return; } (<any> process).__pandoraOriginArgv = Array.from(process.argv); Array.prototype.splice.apply(process.argv, [ 2, process.argv.length - 2, ...(options.args || []) ]); if(options.entryFile) { process.argv[1] = options.entryFile; } const processBootstrap = new ProcessBootstrap(options); process.on('message', (message) => { if (message.action === SHUTDOWN) { processBootstrap.stop().then(() => { if (process.send) { process.send({action: FINISH_SHUTDOWN}); } }).catch(consoleLogger.error); } }); const onProcessTerm = (sig) => { consoleLogger.info(`Process [name = ${options.processName}, pid = ${process.pid}] Receive a signal ${sig}, start to stopping, pid ${process.pid}`); processBootstrap.stop().then(() => { process.exit(0); }).catch((err) => { consoleLogger.error(err); process.exit(1); }); }; process.once('SIGQUIT', onProcessTerm.bind(null, 'SIGQUIT')); process.once('SIGTERM', onProcessTerm.bind(null, 'SIGTERM')); process.once('SIGINT', onProcessTerm.bind(null, 'SIGINT')); processBootstrap.start().then(() => { if (process.send) { process.send({action: PROCESS_READY}); } }).catch((err) => { consoleLogger.error(err); consoleLogger.error('An error occurred during the start of ProcessBootstrap.'); if (process.send) { process.send({action: PROCESS_ERROR, error: err}); } }); } } let cmdDid = false; export function cmd() { if (cmdDid) { return; } cmdDid = true; ProcessBootstrap.cmd(); } // Handing CLI if this module be the main module if (require.main === module || process.env.RUN_PROCESS_BOOTSTRAP_BY_FORCE) { delete process.env.RUN_PROCESS_BOOTSTRAP_BY_FORCE; cmd(); }