emkman
emkman

Reputation: 812

Best way to start main node app from simple script

I'd like to start an app in two different ways depending on the environment.

In package.json:

"scripts": {
    "start": "node start.js" 
}

Then in the script check the environment variable and execute the correct command:

// start.js
var env = process.env.NODE_ENV;

if (env === 'development') {
    //run './node_modules/.bin/nodemon main.js' 
}

if (env === 'production') {
    //run 'node main.js'
}

//do I need to exit?
process.exit(1);

Is exec, fork, or spawn ideal here? I need no communication between start.js and the main.js, and I want the least overhead. I want it to be as close to running the environment specific command directly. My inclination is fork because it will start a new process and the parent will terminate.

UPDATE: I am not interested in alternative solutions that use multiple npm commands. I specifically want to understand the pros/cons/resource use/performance implications of starting one node script from another using the various child_process methods.

Upvotes: 5

Views: 11184

Answers (3)

zangw
zangw

Reputation: 48346

The difference among spawn(), exec() and fork() of child_process as below

require('child_process').spawn() starts sending back data from the child process in a stream as soon as the child process starts executing. When you run this command, it send a system command that will run on its own process rather than executing code within your node process. In this no new V8 instance will be created and only one copy of the node module will be active on the processor. It is used when you want the child process to return large amount of data to Node.

require('child_process').fork() is a special instance of spawn thats runs a new instance of the V8 engine. Which actually means you are creating multiple workers running on the same Node code base for different task.

require('child_process').exec() returns a buffer from the child process. The default buffer size is 200k. It is asynchronous, but it waits for the child process to end and tries to return all the buffered data at once. If your return data from the child process is greater than 200k then you will get maxBuffer exceeded.

According to the source code of PM2

var exec = require('child_process').exec;

The child_process.exec is used to start node.js app. PM2 also has cluster mode, which culster.for() is used here. cluster.fork is implemented on top of child_process.fork.

if (cluster.isMaster) {  
  // Master:
  // Let's fork as many workers as you have CPU cores

  for (var i = 0; i < numCPUs; ++i) {
    cluster.fork();
  }
} else {
  // Worker:
  // Let's spawn a HTTP server
  // (Workers can share any TCP connection.
  //  In this case its a HTTP server
  ...
}

IMO, the PM2 is one good option to start node.js app. It also can start node.js in development mode with PM2-dev. More details could be found here.

Source:

http://www.codingdefined.com/2014/08/difference-between-fork-spawn-and-exec.html https://nodejs.org/api/cluster.html#cluster_cluster_fork_env

Upvotes: 1

arcseldon
arcseldon

Reputation: 37075

I tend to do something like:

var env = process.env.NODE_ENV || 'development';

right in the main bootstrap application file (app.js, main.js, start.js or whatever you named it) because my usual use case is development work locally. So if nothing is set, it uses development, and if I have set an environment variable explicitly it uses that (usually only set for production, but could be anything including test etc).

Then for production, you would just need to set the NODE_ENV environment variable (which cloud services like Heroku make really simple to set up when deploying to the live environment too).

Another pattern you sometimes see is:

var env = process.env.NODE_ENV = process.env.NODE_ENV || 'development';

This is actually also updating the process.env.NODE_ENV assigned value, which means if you have other places also checking for the value of proces.env.NODE_ENV then you don't have to keep also using the "|| 'development'" check. It is not a pattern I tend to use, but you will see it in the wild.

Your npm scripts entry looks good, but there is nothing stopping you from defining others, calling out to shell scripts, setting env variables etc either. If you are going to have one for production, I'd recommend making that explicit:

eg.In package.json:

"scripts": {
    "start": "npm run dev"
    "dev": "nodemon start.js",
    "prd": "NODE_ENV=production node start.js" 
}

That way, there is no confusion as you have to run either:

npm run dev
// same as npm start

or

npm run prd

Above, our dev environment is executed with nodemon, and our production environment with node as requested.

Update Based ON OP Feedback

which child_process method is best to start your main node app from. That was the main point of my question

What you are asking is atypical - however, there are of course options available:

If you wanted to background the node instance, then easy to control this from the command line via bash (&) etc.

However, if you really wish to do this, then in the past I have opted to use an NPM module - cluster.

npm install cluster

This allows you to spawn child instances from a master process - in your case just set the child instance count to 1.

var cluster = require('cluster')
  , app = require('./main');

cluster(app)
  .set('workers', 1)
  // other configuration here

Finally, if you don't wish to use cluster, and really the question was more along the lines of "how to start another node.js application inside node then:

Use child_process.fork(). It is similar to spawn(), but is used to create entire new instances of V8. Therefore it is specially used for running new instances of Node.

var fork = require('child_process').fork;
var child = fork('./main');

There are further options, please see the documentation for details.

Upvotes: 2

Alireza Davoodi
Alireza Davoodi

Reputation: 769

i think the approach not suitable.

in package.json

{
  ...
  "scripts": {
    "start": "NODE_ENV=production node ./app"
  }
  ...
}

an then

npm start

UPDATE 1

If you are in windows machine just use it like this

set NODE_ENV=development&& nodemon server.js

If your machine is not a windows machine, use this

{
...
"scripts": {
 "start": "NODE_ENV=development nodemon ./src/server/app.js"
 }
 ...
}

Upvotes: 2

Related Questions