DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป

DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป is a community of 963,503 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
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!

Top comments (0)

This post blew up on DEV in 2020:

js visualized

๐Ÿš€โš™๏ธ JavaScript Visualized: the JavaScript Engine

As JavaScript devs, we usually don't have to deal with compilers ourselves. However, it's definitely good to know the basics of the JavaScript engine and see how it handles our human-friendly JS code, and turns it into something machines understand! ๐Ÿฅณ

Happy coding!