11
votes

Im using npm scripts, I have some of them that should run in parallel. I've got something like this:

...
scripts: {
   "a": "taskA &",
   "preb": "npm run a",
   "b": "taskB"
}
...

This is fine! But I'd like to kill automatically taskA running the background after taskB has finished.

How can I do that? Thanks!

3

3 Answers

22
votes

I don't believe npm is the best tool to manage complex relationships between processes.

You would be far better served by creating a node script that uses node's child_process module to manage the launching and killing of co-processes, perhaps using spawn.

Having said that, and in the spirit of always trying to provide a direct, usable answer..

You could structure your npm scripts like (assumes bash shell):

scripts:{
    runBoth: "npm runA & npm runB",     // run tasks A and B in parallel
    runA:    "taskA & TASKA_PID=$!",    // run task A and capture its PID into $TASKA_PID
    runB:    "taskB && kill $TASKA_PID" // run task B and if it completes successfully, kill task A using its saved PID
}

The only 'magic' here is that:

  1. when you run a command in the background using the bash shell (which is what happens when you add & to the end), you can discover it PID using $!, but only immediately after the command is run. (See Advanced Bash-Scripting Guide: Chapter 9. Another Look at Variables - 9.1. Internal Variables for its description.)
  2. taskB must call process.exit(0) on success or process.exit(-1) on failure so that the && test is handled correctly. (See this answer for more information.)
2
votes

The npm-run-all package may be what you're looking for:

$ npm install --save npm-run-all

Then in your package.json file:

"scripts": {
    "runA": "taskA",
    "runB": "taskB",
    "runBoth": "npm-run-all -p runA runB"
}

(-p runs them in parallel, use -s for sequential.)

1
votes

Using the concurrently package looks like a less tricky & painful way. This avoids detached processes (&) alltogether. And promises to be more cross-plattform, too.

npm install concurrently --save

and then in package.json

"runBoth": "concurrently \"npm run taskA\" \"npm run taskB\"",

Tested (under Ubuntu 16.04, npm 5.6), also see here.