Reputation: 812
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
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
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
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