Skip to content

Commit

Permalink
Improves kill-logic of child processes.
Browse files Browse the repository at this point in the history
  • Loading branch information
mysticatea committed Nov 11, 2015
1 parent 8c14769 commit bc749bc
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 44 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"clean": "rimraf lib bin coverage",
"lint": "eslint src test",
"build": "npm run clean && npm run lint && babel src --out-dir . --optional runtime,asyncToGenerator",
"test": "npm run lint && babel-node node_modules/isparta/bin/isparta cover node_modules/mocha/bin/_mocha -- test/*.js --require scripts/mocha-babel-hook --timeout 30000",
"testing": "mocha test/*.js --require scripts/mocha-babel-hook --timeout 30000 --watch --growl",
"test": "npm run lint && babel-node node_modules/isparta/bin/isparta cover node_modules/mocha/bin/_mocha -- test/*.js --require scripts/mocha-babel-hook --timeout 12000",
"testing": "mocha test/*.js --require scripts/mocha-babel-hook --timeout 12000 --watch --growl",
"coveralls": "cat coverage/lcov.info | coveralls"
},
"dependencies": {
Expand Down
39 changes: 0 additions & 39 deletions src/lib/kill-task.js

This file was deleted.

7 changes: 4 additions & 3 deletions src/lib/run-task.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {spawn} from "child_process";
import {parse as parseArgs} from "shell-quote";
import killTask from "./kill-task";
import whichNpm from "./which-npm";

const spawn = require(process.platform === "win32" ? "./spawn-win32" : "./spawn-posix");

function detectStreamKind(stream, std) {
return (
stream == null ? "ignore" :
Expand Down Expand Up @@ -52,7 +52,8 @@ export default function runTask(task, stdin, stdout, stderr) {

promise.abort = function abort() {
if (cp != null) {
killTask(cp);
cp.kill();
cp = null;
}
};

Expand Down
59 changes: 59 additions & 0 deletions src/lib/spawn-posix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import cp from "child_process";

// List of child processes that are running currently.
const children = [];

/**
* Removes this process from the children pool.
* @this ChildProcess
*/
function removeFromPool() {
const index = children.indexOf(this);
if (index !== -1) {
children.splice(index, 1);
}
}

/**
* Kills this process and sub processes with the process group ID.
* @this ChildProcess
*/
function kill() {
process.kill(-this.pid);
}

/**
* Launches a new process with the given command.
* This is almost same as `child_process.spawn`.
*
* This detaches the new process to make new process group.
* And if this process exited before the new process exits, this kills the new process.
*
* This returns a `ChildProcess` instance.
* `kill` method of the instance kills the new process and its sub processes with the process group ID.
*
* @param {string} command - The command to run.
* @param {string[]} args - List of string arguments.
* @param {object} options - Options.
* @returns {ChildProcess} A ChildProcess instance of new process.
*/
export default function spawn(command, args, options) {
options.detached = true; // eslint-disable-line no-param-reassign

const child = cp.spawn(command, args, options);
child.on("exit", removeFromPool);
child.on("error", removeFromPool);
child.kill = kill;

// Add to the pool to kill on exit.
children.push(child);

return child;
}

// Kill all child processes on exit.
process.on("exit", () => {
for (const child of children) {
child.kill();
}
});
28 changes: 28 additions & 0 deletions src/lib/spawn-win32.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import cp from "child_process";

/**
* Kills the new process and its sub processes forcibly.
* @this ChildProcess
*/
function kill() {
spawn("taskkill", ["/F", "/T", "/PID", this.pid]);
}

/**
* Launches a new process with the given command.
* This is almost same as `child_process.spawn`.
*
* This returns a `ChildProcess` instance.
* `kill` method of the instance kills the new process and its sub processes forcibly.
*
* @param {string} command - The command to run.
* @param {string[]} args - List of string arguments.
* @param {object} options - Options.
* @returns {ChildProcess} A ChildProcess instance of new process.
*/
export default function spawn(command, args, options) {
const child = cp.spawn(command, args, options);
child.kill = kill;

return child;
}

0 comments on commit bc749bc

Please sign in to comment.