Run a custom npm script with PM2 - node.js

I am currently developing several Telegram bots but I want to keep all of them in the same git repository. The issue is that on the other hand, I want to run them as separate processes.
Since I'm using the Telegraf framework, to run a bot it goes such as: micro-bot src/bot-one/bot.js
The problem comes when doing this with PM2. I've been able to run one of the bots with the npm start script like this:
pm2 start --name "WeatherBot" npm -- start -- -t <
TOKEN>
But I'd like to be able to create custom scripts like this:
"main": "src/weatherWarnBot/bot.js",
"scripts": {
"start": "micro-bot",
"littleAppleBot": "micro-bot src/littleAppleBot/bot.js",
"weatherWarnBot": "micro-bot src/weatherWarnBot/bot.js"
}
But, how would the PM2 command be to run each of the two custom scripts? I was thinking of having the bot tokens set as enviroment variables of the system, for simplification.

Try this:
pm2 start npm -- run littleAppleBot --
pm2 start npm -- run weatherWarnBot --

Use this :-
pm2 start --name "Script Name" npm -- run <YOUR CUSTOM SCRIPT> --

pm2 start npm --name "Your APP Name" -- start

Related

What are the differences between the processes run by npm command:

Recently I made a simple API server using node.js+express. And the script below is a part of my package.json file I use to run with npm commands.
"scripts": {
...
"release": "cross-env NODE_ENV=production MODE=release node server/app.js",
}
After I starts the server with npm run release, I can see multiple processes such as below are running on my Linux server.
/bin/sh /api/node_modules/.bin/cross-env NODE_ENV=development MODE=test node server/app.js
node /api/node_modules/.bin/../cross-env/bin/cross-env.js NODE_ENV=development MODE=test node server/app.js
node server/app.js
I read a related documentation here, but I don't understand what actually happens in background.
What is the order of creating processes? npm => /bin/sh => node /api/.. => node server/app.js ?
What does each process do? All three processes are necessary to run my server?
If I wants to kill the server with pid, which process id should I use?
What is the order of creating processes? npm => /bin/sh => node /api/.. => node server/app.js ?
What does each process do? All three processes are necessary to run my server?
Well, the flow is like this:
NPM is spawned (you run it) inside your shell, npm itself runs with NPX in order to set the local path.
Your npm script spawns a process from a package called cross-env for cross-OS environment variable setting.
That process in turn spawns Node.js (after setting the environment variables)
That's why you see 3 processes. After your server itself run - only the actual server process is needed to run the server.
If I wants to kill the server with pid, which process id should I use?
This one: node server/app.js - since that's your actual server, the others are just "utility processes" (one for the npm script you ran and the other for the environment variables").
It's worth mentioning that in general - servers are run inside containers or other orchestrators/managers that have built-in logic for restarting/killing the process. Typically the orchestrator sends SIGTERM to the process.

Start multiple processes via npm scripts using PM2

I want to start multiple processes by pm2.
I found how to start one process for npm run start:
pm2 start npm -- start
But when I've tried make something like pm2 start npm -- event for npm run event it doesn't start a new process but restarts the first one.
How can I start multiple process by npm and pm2?
Use the --name flag to give each processes a unique name for PM2 to identify them by.
For example:
pm2 start --name=start npm -- start
pm2 start --name=event npm -- run event
Further operations should use the name you have given each process. For example to stop them:
pm2 stop start
pm2 stop event

Running forever script from Google Cloud Platform App Engine startup script

I have edited the startup-script variable for one of my instances running on the Google Cloud Platform App Engine. I'd like it to call a forever script to make sure my node app is running. So I added:
cd /opt/bitnami/apps/myapp
forever start --workingDir /opt/bitnami/apps/myapp/ --sourceDir /opt
/bitnami/apps/myapp/ app.js
after the #!/bin/bash line (also tried without the cd as it's not really necessary based on my command). But once the vm is started, running a forever list doesn't list my forever task as having ever started. If I copy and paste that forever command into a gcloud terminal and run, the task shows up fine and my app starts no problem.
Am I not calling this correctly somehow within the bash script?
The simple answer is that GAE does this by default. No need for forever or PM2. There are certain health checks that GAE does on the Docker container holding your app, and if they do not pass the instance is automatically restarted
If you want granular control over these checks (called Legacy Health Checks) you can add this to your app.yaml file:
health_check:
enable_health_check: True
check_interval_sec: 5
timeout_sec: 4
unhealthy_threshold: 2
healthy_threshold: 2
There is also updated mechanisms (called Updated Health Checks) that are still in beta, but can be used instead
The proper way to start your nodejs app on appengine is to specify the "scripts" field in your package.json, as the documentation
Below is an example borrowed from this sample
"scripts": {
"start": "node ./bin/www",
"test": "cd ..; npm run t -- appengine/analytics/test/*.test.js"
},
If you however, are only interested in running a node script, and not interested in the features that come with Google app engine, then you may simply run it on a Google Compute Engine instance.

Passing environment variables in npm-scripts

I have a package.json with following (simplified) content in the scripts key:
...
scripts: {
"start": "NODE_ENV=${NODE_ENV:=production} node start-app.js",
"poststart": "echo $NODE_ENV"
}
...
From the command line I can run:
npm start
This will run my start-app.js script and set the process.env.NODE_ENV environment variable to "production". See here for syntax explanation.
The poststart will automatically run after start as described here.
However poststart will not "inherit" the NODE_ENV shell environment variable, so the echo command will not echo anything.
My producation code is a little more complex, but what I am trying to accomplish is passing down the NODE_ENV variable from the "starting point" to dependent scripts. Any suggestions/best practices on how to do that?
I dont want to hardcode the NODE_ENV in the poststart, because I might want to do:
NODE_ENV=development npm start
and I want everyting "down the chain" inherit the same environment.
You have a few options:
better-npm-run,which can define an env for each command separately
Instead of a poststart script, you can concatenate commands for npm like so: "start": "NODE_ENV=${NODE_ENV:=production} node start-app.js && echo $NODE_ENV"
Use a process manager in production like pm2. pm2 lets you define environment specific json files with settings such as NODE_ENV. At our company, we successfully run all of our apps in different environments with pm2 (all the while having the same start command)
this is how I did it, first you need to install two dev-dependencies
https://www.npmjs.com/package/env-cmd
this load your env var from your file
https://www.npmjs.com/package/cross-env
this use environment variable in script
example scripts:
"env-cmd ./.config/prod.env cross-env-shell \"docker volume create $DOCKER_VOLUME\""
this load $DOCKER_VOLUME env var from prod.env
update:
starting from env-cmd version 10, you need specify -f flag if you want to use a custom env file path
"env-cmd -f ./.config/prod.env cross-env-shell \"docker volume create $DOCKER_VOLUME\""
If you have small use cased, use better-npm-run. For small cases, it works fine. Somehow if you have a lot of commands and it hard manage. Try, batman-cli. Work well and handle lot of environment-dependent issues
npm i -g batman-cli

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