node env value does not get changed with process manager command - node.js

I am writing NODE_ENV=production pm2 start app to run the node environment into production mode. But somehow when I extract the value with app.get('env') it gives me development value only. So what should be inserted to run node environment into production mode ?

By default we want that PM2 doesn’t change process environment while restarting or reloading. So, In order to change the ENV value of a process just stopping and starting won't work.
You have to either DELETE the process and start again(which I mainly do because when I change envs there are some major changes happening inside, so this method works for me)
pm2 delete app
NODE_ENV=prod pm2 start app
Or, From the Doc "If you want to update them [While restarting/reloading a process], you must use --update-env":
You want to inject a new environment variable to a process (for
example DEBUG): Use DEBUG=* pm2 reload myapp --update-env

Related

PM2 and Node: why am I getting env variable undefined?

Platform: Windows
What I want to do is simple: start pm2 (without any .json scripts) and have my node web app (ExpressJS) access the env. variable.
when I do set
> set MODE=test
and then do
> npm start
I can access process.env.MODE which gives me 'test' exactly as I wanted.
Now I can't seem to figure out how to do this in pm2. If I
> set MODE=test
and then do
pm2 start ./bin/www
I get process.env.MODE is undefined
I also tried
pm2 start ./bin/www -x -- --MODE=test
also tried
set MODE="test" & pm2 start ./bin/www
and
set MODE=test & pm2 start ./bin/www
Nothing seems to work. What am I doing wrong? What should I do instead?
On Windows SET sets an environment variable in the current CMD session. You may need to SET your environment variable in the same CMD session that you are running pm2 from.
Alternately, use SETX to set a permanent environment variable. You need to close and re-open and CMD sessions in order to make an environment variable set with SETX available in all CMD sessions.
refer: https://superuser.com/questions/916649/what-is-the-difference-between-setx-and-set-in-environment-variables-in-windows

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

Redeploying NAR (node.js) archive with PM2

There is node.js app built with Typescript, so it needs to be first "compiled" to JS before it gets run. I'm planning to use NAR (https://github.com/h2non/nar) to build ready-to-deploy package to avoid fiddling with npm install and compiling it on production. I also use PM2 as process manager for node apps.
However as far as I know PM2 can only deploy from git (fetching sources and calling npm install etc. later on), but I couldnt find a way to easily deploy application that is already pre-built.
This is my deploy.yml file contained within archive that I extract with nar extract <package>:
apps:
- script: dist/app.js
merge_logs: true
name: server
instances: 1 # 0 => max, depending on CPU cores
exec_mode: cluster
node_args: --harmony --harmony_destructuring --harmony_default_parameters
log_file: deploy/logs/server.log
pid_file: deploy/pids/server.pid
source_map_support: true
env:
NODE_ENV: production
It works fine when run for the first time, but then when I try to redeploy it (replacing application content with new version) and call pm2 reload all I get errored processes saying they either cannot load ProcessManager from PM2 or cannot find my .env file (which is in place).
As soon as I kill PM2 daemon with pm2 kill and start apps again with pm2 start all deploy.yml it clicks. But this is probably not how PM2 should be used, right?
Do you have any experience with such setup and had similar issues? Or maybe can you point me to another way of running my deployment?

Passing environment variables to node.js using pm2

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"

Can I tell foreman to reload the web app every time a request is made so I can develop decently?

A web app I am writing in JavaScript using node.js. I use Foreman, but I don't want to manually restart the server every time I change my code. Can I tell Foreman to reload the entire web app before handling an HTTP request (i.e. restart the node process)?
Here's an adjusted version of Pendlepants solution. Foreman looks for an .env file to read environment variables. Rather than adding a wrapper, you can just have Foreman switch what command it uses to start things up:
In .env:
WEB=node app.js
In dev.env:
WEB=supervisor app.js
In your Procfile:
web: $WEB
By default, Foreman will read from .env (in Production), but in DEV just run this:
foreman start -e dev.env
You can use rerun for this purpose
You might implement just 2 commands for this:
gem install rerun
rerun foreman start
Then rerun will automatically restart process after any change in your files.
If you use nodemon
, you can do
nodemon --exec "foreman start"
The problem isn't with Foreman so much as it's with how node doesn't reload code on new requests. The solution is to use an npm package like supervisor along with an environment wrapper for Foreman.
First, install supervisor:
npm install -g supervisor
Then, write a wrapper shell script that Foreman can call:
if [ "$NODE_ENV" == "production" ]; then
node /path/to/app.js
else
supervisor /path/to/app.js
fi
Set the wrapper script's permissions to executable by running chmod a+x /path/to/wrapper_script.sh
Lastly, update foreman to use the wrapper script. So in your Procfile:
web: /path/to/wrapper_script.sh
Now when you run Foreman and your node app isn't running in production, it should reload on every request.
I feel like Peter Ehrlich's comment on the original question deserves to be an answer on its own. I think a different Procfile for local/dev is definitely the best solution: https://stackoverflow.com/a/10790514/133720
You don't even need to install anything new if you use node-dev.
Your .env file loaded from Procfile:
NODECMD=node-dev
Your Procfile:
web: $NODECMD app/server.js
Your foreman command
foreman start -e dev.env -p 9786
And in your production env (heroku) set an environment variable:
NODECMD=node

Resources