From edf9ced454d3bd5bdeef38d54865ea40fd9c87a2 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 25 Jan 2017 11:11:33 -0700 Subject: [PATCH] Added PID support --- .env-e2e | 3 --- bin/cli | 48 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- scripts/poste2e.sh | 10 ++++++++++ scripts/pree2e.sh | 9 +++++---- util.js | 19 +++++++++++++----- 6 files changed, 78 insertions(+), 13 deletions(-) delete mode 100644 .env-e2e create mode 100755 scripts/poste2e.sh diff --git a/.env-e2e b/.env-e2e deleted file mode 100644 index eefd18d51..000000000 --- a/.env-e2e +++ /dev/null @@ -1,3 +0,0 @@ -TALK_SESSION_SECRET=imasecretlookatme -TALK_ROOT_URL=http://localhost:3000 -TALK_MONGO_URL=mongodb://localhost/test diff --git a/bin/cli b/bin/cli index c5c61fbf6..107d0a9ba 100755 --- a/bin/cli +++ b/bin/cli @@ -7,6 +7,8 @@ const program = require('commander'); const pkg = require('../package.json'); const dotenv = require('dotenv'); +const fs = require('fs'); +const util = require('../util'); //============================================================================== // Setting up the program command line arguments. @@ -15,6 +17,7 @@ const dotenv = require('dotenv'); program .version(pkg.version) .option('-c, --config [path]', 'Specify the configuration file to load') + .option('--pid [path]', 'Specify a path to output the current PID to') .parse(process.argv); if (program.config) { @@ -27,6 +30,40 @@ if (program.config) { } } +// If the `--pid` flag is used, put the current pid there. +if (program.pid) { + let pidPath = program.pid; + + if (!/\//.test(pidPath)) { + if (!/\.pid/.test(pidPath)) { + pidPath += '.pid'; + } + pidPath = `/tmp/${pidPath}`; + } + + fs.writeFile(pidPath, `${process.pid.toString()}\n`, (err) => { + if (err) { + console.error(`Can't write PID file: ${err}`); + throw err; + } + + // Add the cleanup for the fs onto the shutdown. + util.onshutdown([ + () => new Promise((resolve, reject) => { + + // Remove the pid file. + fs.unlink(pidPath, (err) => { + if (err) { + return reject(err); + } + + return resolve(); + }); + }) + ]); + }); +} + // Perform rewrites to the runtime environment variables based on the contents // of the process.env.REWRITE_ENV if it exists. This is done here as it is the // entrypoint for the entire application. @@ -43,4 +80,15 @@ program // If there is no command listed, output help. if (!process.argv.slice(2).length) { program.outputHelp(); + return; } + +// The ensures that the child process that is created here is always cleaned up +// properly when the parent process dies. +util.onshutdown([ + (signal) => { + if ((program.runningCommand.killed === false) && (program.runningCommand.exitCode === null)) { + program.runningCommand.kill(signal); + } + } +]); diff --git a/package.json b/package.json index c0cf30802..26cd2d5d4 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "test-watch": "TEST_MODE=unit NODE_ENV=test mocha --compilers js:babel-core/register --recursive -w tests", "pree2e": "NODE_ENV=test scripts/pree2e.sh", "e2e": "NODE_ENV=test nightwatch", - "poste2e": "kill -15 $(ps aux | grep './bin/cli -c .env-e2e serve --jobs' | awk '{print $2}')", + "poste2e": "NODE_ENV=test scripts/poste2e.sh", "embed-start": "NODE_ENV=development npm run build && ./bin/cli serve --jobs", "postinstall": "npm run build" }, diff --git a/scripts/poste2e.sh b/scripts/poste2e.sh new file mode 100755 index 000000000..1a8279da1 --- /dev/null +++ b/scripts/poste2e.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# If there is a PID file from the e2e tests... +if [ -e /tmp/talk-e2e.pid ] +then + + # Then kill the running talk server. + kill $(cat /tmp/talk-e2e.pid) + +fi diff --git a/scripts/pree2e.sh b/scripts/pree2e.sh index 17da70f87..267a2617f 100755 --- a/scripts/pree2e.sh +++ b/scripts/pree2e.sh @@ -4,12 +4,13 @@ selenium-standalone install # Creating Admin Test User -./bin/cli-users create --flag_mode --email "admin@test.com" --password "testtest" --name "AdminTestUser" --role "admin" +./bin/cli users create --flag_mode --email "admin@test.com" --password "testtest" --name "AdminTestUser" --role "admin" # Creating Moderator Test User -./bin/cli-users create --flag_mode --email "moderator@test.com" --password "testtest" --name "ModeratorTestUser" --role "moderator" +./bin/cli users create --flag_mode --email "moderator@test.com" --password "testtest" --name "ModeratorTestUser" --role "moderator" # Creating Commenter Test User -./bin/cli-users create --flag_mode --email "commenter@test.com" --password "testtest" --name "CommenterTestUser" +./bin/cli users create --flag_mode --email "commenter@test.com" --password "testtest" --name "CommenterTestUser" -./bin/cli -c .env-e2e serve --jobs & +# Start the server and write the PID to a file to be killed later. +./bin/cli --pid /tmp/talk-e2e.pid serve --jobs & diff --git a/util.js b/util.js index b081078e7..261b66f85 100644 --- a/util.js +++ b/util.js @@ -1,3 +1,4 @@ +const debug = require('debug')('talk:util'); const util = module.exports = {}; /** @@ -11,10 +12,16 @@ util.toshutdown = []; * Calls all the shutdown functions and then ends the process. * @param {Number} [defaultCode=0] default return code upon sucesfull shutdown. */ -util.shutdown = (defaultCode = 0) => { +util.shutdown = (defaultCode = 0, signal = null) => { + + if (signal) { + debug(`Reached ${signal} signal`); + } + Promise - .all(util.toshutdown.map((func) => func ? func() : null).filter((func) => func)) + .all(util.toshutdown.map((func) => func ? func(signal) : null).filter((func) => func)) .then(() => { + debug('Shutdown complete, now exiting'); process.exit(defaultCode); }) .catch((err) => { @@ -32,6 +39,8 @@ util.shutdown = (defaultCode = 0) => { */ util.onshutdown = (jobs) => { + debug(`${jobs.length} jobs registered`); + // Add the new jobs to shutdown to the object reference. util.toshutdown = util.toshutdown.concat(jobs); }; @@ -39,6 +48,6 @@ util.onshutdown = (jobs) => { // Attach to the SIGTERM + SIGINT handles to ensure a clean shutdown in the // event that we have an external event. SIGUSR2 is called when the app is asked // to be 'killed', same procedure here. -process.on('SIGTERM', () => util.shutdown()); -process.on('SIGINT', () => util.shutdown()); -process.once('SIGUSR2', () => util.shutdown()); +process.on('SIGTERM', () => util.shutdown(0, 'SIGTERM')); +process.on('SIGINT', () => util.shutdown(0, 'SIGINT')); +process.once('SIGUSR2', () => util.shutdown(0, 'SIGUSR2'));