DEV Community

Tyler Smith
Tyler Smith

Posted on • Updated on

Exiting Node.js when programmatically using "Concurrently" to run multiple scripts

Concurrently is a Node package that allows you to run multiple scripts at the same time in Node.js. It's especially useful if you want to run your app's front-end and back-end from a single NPM command.

Concurrently also has a Node API to start concurrent processes programmatically from within a script file. However, if you use concurrently programmatically, it may be unclear how to make sure everything shuts down cleanly when you kill the process in your command line.

Here's an example of what programmatic usage of Concurrently may look like:

// package.json
{
  // ...other config properties
  "scripts": {
    "start": "node bootstrap.js",
  },
}
Enter fullscreen mode Exit fullscreen mode
// bootstrap.js
const concurrently = require('concurrently');

concurrently([
  "node back-end/server.js",
  "react-scripts start"
], {
  prefix: 'name',
  killOthers: ['failure', 'success'],
  restartTries: 3,
});
Enter fullscreen mode Exit fullscreen mode

The killOthers property will ensure that all of Concurrently's processes shut down when one of them shuts down, but there's a problem. When you exit this script from the command line, you only exit Concurrently's processes: the calling script's process doesn't exit. This can cause some unexpected and undesirable behavior.

Thankfully, if you want the parent process to terminate when you exit Concurrently's processes, it's only a few extra lines of code.

// bootstrap.js
const concurrently = require('concurrently');

concurrently([
  "node back-end/server.js",
  "react-scripts start"
], {
  prefix: 'name',
  killOthers: ['failure', 'success'],
  restartTries: 3,
}).then(
    function onSuccess(exitInfo) {
      // This code is necessary to make sure the parent terminates 
      // when the application is closed successfully.
      process.exit();
    },
    function onFailure(exitInfo) {
      // This code is necessary to make sure the parent terminates 
      // when the application is closed because of a failure.
      process.exit();
    }
  );
Enter fullscreen mode Exit fullscreen mode

When Concurrently's processes terminate, Concurrently calls its then(success, failure) method. The success and failure parameters accept a function that fires after Concurrently's processes terminate, either through a success or failure.

In my code example above, I've named these onSuccess() and onFailure() to help me remember which is which, but you could call these anything, or leave them nameless anonymous functions. Both receive an argument with information about each command that has been run. You can read more about these arguments in the docs.

Inside my onSuccess() and onFailure() functions, I'm calling process.exit(), which exits the main node process. Now, when I exit the processes from my command line, it exits Concurrently's scripts and the Node script that called it.

By calling Concurrently programmatically in a Node script, you can keep your package.json file more manageable and add additional logic to how Concurrently behaves.

Let me know if you found this post helpful!

Discussion (0)