I'm trying to use pm2 to manage a node.js cluster
pm2 start . -i 3
I'm currently running the app on heroku and using a Procfile with the above command, but I cannot figure out how to configure pm2 to use the existing PORT env var. Something like pm2 start . -p $PORT
What am I missing?
You can use an environment variable.
For example:
NODE_PORT=3002 pm2 start -i 0 app.js
Here is how to read the value in app:
console.log(process.env.NODE_PORT);
Or, if you are building an Express app:
PORT=3002 pm2 start -i 0 ./bin/www
Express loads PORT automatically when the application starts.
You need to use -- to tell pm2 to stop parsing his options and give the rest to the program, then when you spawn direct binary, you need to tell pm2 that you don't want to use nodejs, so :
pm2 start rethinkdb --interpreter none -- --port 8082
You see you need -- --port 8082
An easy way of telling your server application on which port to run is through PM2's
ecosystem configuration files
in conjunction with properly configured use of $PORT environment vars inside your server application. That means your server reads $PORT environment var to start the server or microservice on specified port.
There are different formats available you can choose for the file to have. I personally use the CommonJS module format (amongst other options are JSON and YAML).
Inside ecosystem.config.js you specify one entry object for each server instance you want to launch through PM2.
The point is that you can also specify environment vars for the different processes and that way you can setup $PORT for all the processes. The following is an example config for three different processes.
module.exports = {
apps : [
{
name : "Main API server",
script : "./backend/dist/main.js",
instances : "2",
exec_mode : "cluster",
env: {
NODE_ENV: "production",
PORT: 4300
}
},
{
name : "Worker server 1",
script : "./backend-worker/dist/main.js",
instances : "1",
exec_mode : "fork",
env: {
NODE_ENV: "production",
PORT: 4000,
},
},
{
name : "Worker server 2",
script : "./backend-worker/dist/main.js",
instances : "1",
exec_mode : "fork",
env: {
NODE_ENV: "production",
PORT: 4001,
}
},
]
}
One note: This configuration uses PM2 as a loadbalancer for the first process that runs as cluster on two cores. The other (worker-)processes are run each on is on process on the specified port.
An example snippet of server startup code using the environment $PORT var for a NodeJS server is following:
// ...
const port = (process.env.PORT) ? process.env.PORT : 4300
console.log('$PORT: ', port)
const server = await app.listen(port, '0.0.0.0')
// ...
When you have all in place you simply call following to startup your servers:
pm2 start ecosystem.config.js
Related
How would I start a pm2 process with the —max-http-header-size node option, as well as name the process.
I have a server with multiple micro-services, one of the services is a web scraper.
This web scraper accepts requests with headers over the nodejs default 8kb limit. So, to run my app locally have to add the --max-http-header-size node option.
I've cloned my app to the server, but don't know how to set --max-http-header-size, nor do I know how to name the process within the pm2 start command.
So far my attempts have looked like this.
// this sets the name, but I don't know how to add the option `--max-http-header-size`
pm2 start npm --name "{REPONAME}" -- start
pm2 start node --name "scraper" --max-http-header-size 15000 app.js
pm2 start node --max-http-header-size 15000 app.js -- --name "scraper"
The accepted answer by David Harvey did not work for me as of Node 16. Instead, I had to use node_args, something like this:
{
"apps" : [{
"name" : "myapp",
"script" : "./app.js",
"node_args": "--max-http-header-size=256000",
"env": {
"NODE_ENV": "production",
}
}]
}
What you're looking for is called environment variables! You can pass environment variables to pm2 using a file that loads your server like this:
module.exports = {
apps : [
{
name: "myapp",
script: "./app.js",
watch: true,
node_args: "--max-http-header-size=16000"
}
]
}
Here's more about it too:
https://pm2.keymetrics.io/docs/usage/environment/
When I run my Node.js express app using node command everything works fine!
When using pm2 server./bin/www` my pm2 status is something like this:
And my app works in this situation. Also when I use pm2 start bin "./bin/www" -i 0 my pm2 list shows:
And yet again my app works. But using following config file:
module.exports = {
apps: [{
name: 'cdn',
script: './bin/www',
instances: 0,
exec_mode: 'cluster',
watch: true,
env: {
NODE_ENV: 'production',
PORT: process.env.PORT || '5555',
}
}]
};
the application while listening on the specified port does not work and prints no error messages and my pm2 status is:
How should I use config file correctly?
Maybe you forgot .config.js in your ecosystem filename.
I lost hours of my day looking for the exact same problem yours and a ignored line of pm2 docs alerts me what I forgot (a weird requirement).
Note that using a Javascript configuration file requires to end the file name with .config.js
I have a node server running on pm2 which depends on some external services.
When those servers go down I pm2 starts restarting my app, but this will keep going until it clogs up my cpu and ram on the server, restarting as much as 50 times a minute.
Is there a way to limit the numbers of restarts on pm2? There is a way to restart the server when the server reaches a certain RAM memory level, so I would hope this feature I am asking for exists.
You can use combination of max_restarts and min_uptime to restrict the app to restart consecutively.
number of consecutive unstable restarts (less than 1sec interval or custom time via min_uptime) before your app is considered errored and stop being restarted
More information about max_restarts and min_uptime is available here
Use PM2 ecosystem.config.js file like this:
module.exports = {
apps : [{
name: "app",
script: "./app.js",
merge_logs: true,
max_restarts": 50, //Here you can define your max restarts
instances: "max",
max_memory_restart: "200M",
env: {
NODE_ENV: "development",
},
env_production: {
NODE_ENV: "production",
}
}]
}
Start your server by following command:
pm2 start ecosystem.config.js //uses variables from `env`
pm2 start ecosystem.config.js --env production //uses variables from `env_production`
For more details see below link:
PM2 Runtime | Guide | Ecosystem File
Options for config file if you have: ecosystem.config.js
{
watch_delay: 5000,
exp_backoff_restart_delay: 100,
restart_delay: 1000,
max_restarts: 2,
min_uptime: 5000,
autorestart: false,
}
Otherwise, give the same command line, as below:
pm2 start app.js --restart-delay=3000
pm2 start app.js --no-autorestart
They themselves know the issue, so see the 1st link below:
https://pm2.keymetrics.io/docs/usage/restart-strategies/
https://pm2.keymetrics.io/docs/usage/process-management/
Mine got fixed only after watch_delay: 5000, and nothing else was required.
I am trying to pass some arguments to my Express application which is run by pm2. There wasn't any hint in their documentation to do so, but apparently it's possible to pass some EV to your node application like SOME_STUFF=xxx pm2 start app.js.
Note - after updating environment variables in your environment, you must do the following:
pm2 restart all --update-env
ask me how I know...
Edit: also look for a .env file in the node source directory...
It's actually possible and I'm pretty sure it was in PM2's documentation some time ago.
Anyways, that's what you need to do:
pm2 start app.js -- -some_stuff xxx
Basically, add -- and then you can add your own app parameters.
Managed to find the source, it was hidden quite well: http://pm2.keymetrics.io/docs/usage/quick-start/#42-ways-of-starting-processes
I was having issues passing parameters using pm2 start app.js -- -some_stuff xxx so I opted to do this instead: SOME_STUFF=xxx OTHER_STUFF=abc pm2 start app.js.
Then when I ran pm2 logs I was able to see that my app successfully started and that the environment variables were set correctly where as before I was seeing errors around these variables when I ran pm2 logs.
The environment variables don't always update unless you force them to.
SOME_STUFF=xxx pm2 start app.js --update-env
You should pass ENV in ecosystem.config.js
ecosystem.config.js (in the root)
module.exports = {
apps: [
{
name: "project-name",
exec_mode: "cluster",
instances: "1",
script: "./server/index.js", // your script
args: "start",
env: {
NODE_ENV: "production",
SOME_ENV: "some_value"...
},
},
],
};
In the console:
pm2 start ecosystem.config.js
There is information about configuration of ENV in PM2 official documentation
My node app (sveltekit build) starts in my ubuntu server when I use
node build/index.js
and includes enviroment variables
so with pm2 I found that my app starts with envs starting it:
pm2 "node build/index.js"
I am using pm2 to start my app but I'm not able to pass argument to it. The command I am using is pm2 start app.js -- dev. Though this works with forever.
If you want to pass node arguments from CLI then
pm2 start myServer.js --node-args="--production --port=1337"
.
Edited
you can add any arguments after --
pm2 start app.js -- --prod --second-arg --third-arg
Sails docs for deploymemt.
You can do as stated in this ticket: https://github.com/Unitech/pm2/issues/13
Though if you're passing the environment you may want to consider leveraging environment variables. With this you create a variable which can be accessed by any process in that environment with process.env.*.
So you have a configuration file config.json:
{
"dev": {
"db": {
"hosts":["localhost"],
"database": "api"
},
"redis": {
"hosts": ["localhost"]
}
},
"staging": {
"db": {
"hosts":["1.1.1.1"],
"database": "api"
},
"redis": {
"hosts": ["2.2.2.2"]
}
},
"production": {
"db": {
"hosts":["1.1.1.1", "1.1.1.2", "1.1.1.3"],
"database": "api"
},
"redis": {
"hosts": ["2.2.2.2", "2.2.2.3"]
}
}
}
Then you import your config:
var config=require('./config.json')[process.env.NODE_ENV || 'dev'];
db.connect(config.db.hosts, config.db.database);
Then you'd set the variable in your environment via shell:
export NODE_ENV=staging
pm2 start app.js
The environment variable will last as long as your session. So you'll have to set it in the ~/.bashrc file for that user for the variable to persist. This will set the variable every session.
PM2 has a deploy system which allows you to set an environment variable each time before your app is daemonized. This is how daemons in POSIX systems typically take parameters, because those parameters aren't lost with the process. Given with your circumstance it might not matter so much, but its a good practice.
Moreover you should consider stop/starting locally, and restarting(if in cluster mode) whenever possible to prevent downtime when in production.
It is possible to define arguments with the process.
You can define a new process in ecosystem.config.js with an args key, like so:
{
name : 'my-service',
script : './src/service.js',
args : 'firstArg secondArg',
},
{
name : 'my-service-alternate',
script : './src/service.js',
args : 'altFirstArg altSecondArg',
}
Here, the two processes use the same file (service.js), but pass different arguments to it.
Note that these arguments are handled within service.js.
In my case I just used process.argv[2] to get the first argument, and so on.
You can send arguments to your script by passing them after --. For example: pm2 start app.js -i max -- -a 23 // Pass arguments after -- to app.js
I have tested and it works in my windows machine. Below is the complete solution to pass arguments to nodejs app using pm2.
** There are also 2 types of argument
node-args - to use before npm start
args - to use in your node program
There are 2 ways to pass arguments with pm2.
Option 1: pass by argument with pm2 commands.
Option 2: by using config file e.g ecosystem.config.js
Option 1 (Pass arg by commands):
pm2 start app/myapp1.js --node-args="--max-http-header-size=80000" -- arg1 arg2
//Access the arg as below in your node program.
console.log(process.argv[2]); // arg1
console.log(process.argv[3]); // arg2
Option 2 (Using config file):
If you are using ecosystem.config.js. you can define with the following configuration:
{
name: 'my-app',
script: 'app\\myapp1.js',
env: {
NODE_ENV: 'DEV',
PORT : 5051
},
node_args: '--max-http-header-size=80000',
args : 'arg1 arg2',
instances: 1,
exec_mode: 'fork'
}
To start as dev mode:
pm2 start --name myapp app/myapp1.js -- .\ecosystem.config.js
To start as production mode, just add --env=production
pm2 start --name myapp app/myapp1.js -- .\ecosystem.config.js --env=production
//Access the arg as below in your node program.
console.log(process.argv[2]); // arg1
console.log(process.argv[3]); // arg2
I always use PM2 to run my python scripts in Linux environment. So consider a script has a single parameter and needs to run continously after some amount if time, then we can pass it like this:
pm2 start <filename.py> --name <nameForJob> --interpreter <InterpreterName> --restart-delay <timeinMilliseconds> -- <param1> <param2>
filename.py is Name of the python script, without <> symbols, I want to run using PM2
nameForJob is the Meaningful name for the job, without <> symbols
InterpreterName is the python interpreter for running script, usually it is python3 in linux
timeinMilliseconds is the time our script needs to wait and re-run again
param1 is the first parameter for the script
param2 is the second parameter for the script.
Well there are 2 ways you can do to pass the parameters from pm2 to nodejs in CLI:
pm2 start app.js -- dev --port=1234 (note there is an extra space between -- and dev)
pm2 start app.js --node-args="dev --port=1234"
Both ways, you will find these values exist in process.argv (['dev','--port=1234'])
You can pass args for node just like that:
NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_ENV=dev pm2 start server.js --name web-server
I'll complement the answers above for npm scripts
For npm scripts
// package.json
{
"scripts": {
"start": "pm2 start --node-args=\"-r dotenv/config\" index.js"
}
}
npm run start runs pm2 start for index.js with node-args -r dotenv/config which include environment variables from .env file with dotenv
From the pm2 docs
//Inject what is declared in env_production
$ pm2 start app.js --env production
//Inject what is declared in env_staging
$ pm2 restart app.js --env staging
You need to start pm2 with something like:
pm2 start app.js --name "app_name" -- arg1 arg2
Then in your code, you can get your args with:
console.log(process.argv);
process.argv is a list like this:
[
'/usr/local/bin/node',
'/usr/local/lib/node_modules/pm2/lib/ProcessContainerFork.js',
'arg1',
'arg2'
]