Passing and Reading Parameters in PM2 - node.js

I want to pass command line arguments to my script.
In forever I used to pass arguments like
forever start example.js 8080
I am unable to figure out how to do it in PM2.
I tried
pm2 start KratosReq.js -- -p 8080
but while reading from process.argv, the array contains
[ 'node', '/usr/local/lib/node_modules/pm2/lib/ProcessContainerFork.js' ]

Pm2 wrap your init script and fork node processes(cluster mode) , i think that is why you have that output , looking for declare enviroment variables in pm2 , you can use a json file to start up your server , or you can just start passing --node-args argument(checking pm2 help , there is that argument) , something like :
pm2 start KratosReq.js --node-args="-p=8080"
Hope this could help.

Related

Passing JSON File to PM2 as a node argument

I have a NodeJS app which needs to start the server with the following parameter: start server.js --config=config.json. Then in the server.js I use NodeUtils.getArgs() and
JSON.parse() to get all the parameters of the config.json file. This works well.
Now, I want to start the server with PM2, but I am not being able.
If I try with pm2 start server.js --node-args"--config=config.json" I get a node: bad option: --config=config.json. I tried with a lot of options but none of them works.
How can I do it? Thanks
EDIT: After starting pm2, if it gets an error, you must pm2 delete all.
You can pass your own arguments after --, so you can do this:
pm2 start server.js -- -config=config.json

How can I check if my pm2 app NODE_ENV is getting set?

So I just deployed a site with node and pm2 for the first time and I'm going back and doing some optimization and reading best practices, etc.
I read that you can get a lot of benefit by setting NODE_ENV=production.
I found this in the pm2 docs:
[process.json]
"env_production" : {
"NODE_ENV": "production"
}
...
$ pm2 start process.json --env production
So, I did it but I have no idea if it is working. While trying to figure out how to check it I learned to try:
$ node
> process.env.NODE_ENV
> undefined
So, that's not a good sign.. but, with my limited understanding of how the low level stuff works, I can guess that maybe pm2 launches each app as a separate node process? So maybe I'm not in the right process when I try to check it.
Also, I don't know if I have to make a new ~/.pm2/dump.pm2 file because maybe whenever that is maybe overriding the options I set? (because I used pm2 startup).
How do I check if my pm2 app's NODE_ENV is set?
To answer the actual question in the title:
Within your script, for me my Express app's app.js file, you can use process.env.NODE_ENV to get the current value of NODE_ENV and log that out if you want.
An even better way is to use PM2's Process Metrics module, aka pmx.
yarn add pmx
or
npm install pmx --save
then
const Probe = require('pmx').probe()
Probe.metric({
name : 'NODE_ENV',
value : function() {
return process.env.NODE_ENV
}
})
Now it will show up in calls to pm2 monit (bottom left).
To change your environment:
It is necessary that you kill and restart the process to change your environment.
$ pm2 kill && pm2 start pm2.json --env production
The following isn't good enough:
pm2 restart pm2.json --env production
You can also check your NODE_ENV via running pm2 show <yourServerName>. This will output info about your running server including node env.
In addition, you can check your environment variables via running pm2 env 0. This will show all the environment variables for the running node process.
Start it with npm by adding this to your package.json:
"scripts": {
"myScript": "NODE_ENV=production pm2 start server.js"
}
Then
npm start myScript
You can do it directly too, but this is easy to manage, automate wth crontab and is in your source control...
Your process.json file is incomplete. Try using something like this:
[process.json]
{
"name" : "MyApp",
"script" : "myapp.js",
"env_production" : {
"NODE_ENV": "production"
}
}
Then add logging into your code, preferably somwhere on startup:
console.log("NODE_ENV : ", process.env.NODE_ENV);
Now start the application:
pm2 start process.json --env production
Lastly watch app logs:
pm2 logs MyApp
This should do it.
May be at the start of your server script you can print the value of the environment variable and then check the PM2 logs. Use the following code to print your environment variable value:
console.log('process.env.NODE_ENV:', process.env.NODE_ENV);
And then use the following code to see the PM2 logs
pm2 logs app_name
Here app_name is your process name as indicated by the entry in the process.json file.
You can set Environment variable for pm2 specifically.
go to /etc/systemd/system/ location.
you can see a file named pm2-username.service
file. (eg: pm2-root.service ) you can directly add an Enviorment variable for pm2.
for me, it was LD_LIBRARY_PATH . so I added the line as below after the PATH variable.
Environment=PATH=/usr/local/lib......
Environment=LD_LIBRARY_PATH=/opt/oracle/instantclient_21_1
after that, you can restart or start the node application with update-env flag,
pm2 start yourapp --update-env
try pm2 env <app_name/id> also you can find NODE_ENV in pm2 show <app_name/id>
In your terminal just type:
echo NODE_ENV
it will print current selected environment variable

How to pass execution arguments to app using PM2?

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'
]

Node.js arguments when using forever

I'm currently using forever to run my node.js application in our development environment. What I am currently struggling with is how to pass node.js arguments when using "forever start"
Here is an example where I need to pass a number and a date to node. It's not working so any help would be appreciated.
forever -c 'node 8010 "2014-11-11 12:00:00"' start app.js
According to the documentation, the script arguments come after the call.
https://github.com/nodejitsu/forever
usage: forever [action] [options] SCRIPT [script-options]
forever start app.js 8010 "2014-11-11 12:00:00"
The usage of nconf https://github.com/flatiron/nconf in your project is highly recommended to grab those params.

Node.js forever with environment variable

The command I run on my server to start my node app is:
sudo IS_PROD=1 node app.js
I have forever installed but can't seem to pass in the environment variable.
sudo IS_PROD=1 forever node app.js
Doesn't seem to do the trick. I have tried several varieties of this. How do I either execute this command successfully or permanently set the environment variable?
First of all you should skip the node thing in you command, it should not be there, you should not be able to execute that. forever automatically starts your script using nodejs. Instead you should do like this;
sudo IS_PROD=1 forever app.js
Probably you, instead of starting your server in foreground, will want to start your server as a daemon. eg.
sudo IS_PROD=1 forever start app.js
This will create a process in the background that will watch your node app and restart it when it exits. For more information see the readme.
Both of these methods preserves the environment variables, just like when you are just using node.
app.js:
console.log(process.env.IS_PROD);
Using node (v0.8.21)
$ node app.js
undefined
$ IS_PROD=1 node app.js
1
$ sudo IS_PROD=1 node app.js
1
Using forever (v0.10.0)
$ forever app.js
undefined
$ IS_PROD=1 forever app.js
1
$ sudo IS_PROD=1 forever app.js
1
Documentation:
process.env
An object containing the user environment. See environ(7).

Resources