Skip to content

Commit

Permalink
Add cleanup option.
Browse files Browse the repository at this point in the history
As spawned processes are not cleaned up when the main process dies
this option adds the abilitiy to kill those when the spawning process
dies.

Closes sindresorhus#51
  • Loading branch information
dignifiedquire committed Aug 3, 2016
1 parent b15483a commit ad4062a
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 2 deletions.
7 changes: 7 additions & 0 deletions fixtures/sub-process
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env node
'use strict';

var m = require('../');

var cp = m('forever', {cleanup: true});
console.log(cp.pid);
15 changes: 14 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var npmRunPath = require('npm-run-path');
var isStream = require('is-stream');
var _getStream = require('get-stream');
var pathKey = require('path-key')();
var onExit = require('signal-exit');
var errname = require('./lib/errname');

var TEN_MEBIBYTE = 1024 * 1024 * 10;
Expand All @@ -33,7 +34,8 @@ function handleArgs(cmd, args, opts) {
stripEof: true,
preferLocal: true,
encoding: 'utf8',
reject: true
reject: true,
cleanup: false
}, parsed.options);

if (opts.preferLocal) {
Expand Down Expand Up @@ -146,6 +148,13 @@ module.exports = function (cmd, args, opts) {
var maxBuffer = parsed.opts.maxBuffer;
var spawned = childProcess.spawn(parsed.cmd, parsed.args, parsed.opts);

var removeExitHandler;
if (parsed.opts.cleanup) {
removeExitHandler = onExit(function () {
spawned.kill();
});
}

var promise = Promise.all([
processDone(spawned),
getStream(spawned, 'stdout', encoding, maxBuffer),
Expand All @@ -159,6 +168,10 @@ module.exports = function (cmd, args, opts) {
var code = result.code;
var signal = result.signal;

if (removeExitHandler) {
removeExitHandler();
}

if (err || code !== 0 || signal !== null) {
if (!err) {
err = new Error('Command failed: ' + joinedCmd + '\n' + stderr + stdout);
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,14 @@
"npm-run-path": "^1.0.0",
"object-assign": "^4.0.1",
"path-key": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
},
"devDependencies": {
"ava": "*",
"cat-names": "^1.0.2",
"coveralls": "^2.11.9",
"is-running": "^2.0.0",
"nyc": "^6.4.0",
"xo": "*"
},
Expand Down
8 changes: 7 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- [Improved Windows support.](https://github.com/IndigoUnited/node-cross-spawn#why)
- Higher max buffer. 10 MB instead of 200 KB.
- [Executes locally installed binaries by name.](#preferlocal)

- [Cleans up spawned processes when the parent process dies](#cleanup)

## Install

Expand Down Expand Up @@ -138,6 +138,12 @@ Default: `true`

Setting this to `false` resolves the promise with the error instead of rejecting it.

#### cleanup

Type: `boolean`<br>
Default: `false`

Setting this to `true` keeps track of the spawned process and `kill`s it when the parent process exits.

## License

Expand Down
22 changes: 22 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import stream from 'stream';
import childProcess from 'child_process';
import test from 'ava';
import getStream from 'get-stream';
import isRunning from 'is-running';
import m from './';

process.env.PATH = path.join(__dirname, 'fixtures') + path.delimiter + process.env.PATH;
Expand Down Expand Up @@ -276,3 +277,24 @@ cmd.title = (message, expected) => `cmd is: ${JSON.stringify(expected)}`;
test(cmd, ' foo bar', 'foo', 'bar');
test(cmd, ' baz quz', 'baz', 'quz');
test(cmd, '');

async function spawnAndKill(t, signal) {
const cp = m('sub-process');
let pid;

cp.stdout.on('data', chunk => {
pid = parseInt(chunk.toString(), 10);
t.is(typeof pid, 'number');

setTimeout(function () {
process.kill(cp.pid, signal);
}, 100);
});

await t.throws(cp);
t.false(isRunning(cp.pid));
t.false(isRunning(pid));
}

test('cleanup - SIGINT', spawnAndKill, 'SIGINT');
test('cleanup - SIGKILL', spawnAndKill, 'SIGTERM');

0 comments on commit ad4062a

Please sign in to comment.