Realmente, pm2 es un sistema que nos permite gestionar los procesos activos en una máquina o servidor, y no tiene relación directa con NodeJS, sin embargo, se suele utilizar para gestionar el servicio de NodeJS, aunque es agnóstico a otras tecnologías.
¿Qué es PM2?
PM2 es un sistema para gestionar los procesos que queremos mantener activos en una máquina. Esto nos permite dejar activos ciertos servicios de forma más cómoda, controlada y automatizada, sin tener que hacerlo de forma manual.
Instalación de PM2
Para instalar PM2, necesitaremos tener instalado NodeJS, por lo que si ya lo tenemos, sólo tenemos que instalarlo de forma global:
$ npm install -g pm2
Esto pondrá a nuestra disposición el comando pm2
, mediante el cuál podemos gestionar los procesos que queremos mantener activos.
Añadir nuestra app a PM2
Para empezar, vamos a crear un servidor muy sencillo con lo que hemos visto en el apartado de Introducción a Express. Creamos un fichero index.js
como el siguiente:
import express from "express";
const app = express();
const HOST = "localhost";
const PORT = 4321;
app.get("/", (req, res) => res.send("Home"));
app.get("/about", (req, res) => res.send("About Page"));
app.get("/faq", (req, res) => res.send("FAQ Page"));
app.listen(PORT, HOST, () => {
console.log(`Server running at http://localhost:${PORT}/`);
});
Observa que este servidor está escuchando en http://localhost:4321
y tiene los endpoints /
, /about
y /faq
, por si quieres probarlos cuando lo arranques.
Para ejecutar esta aplicación en desarrollo, necesitamos escribir node index.js
en una línea de comandos, sin embargo, en lugar de esto podemos añadir el comando a PM2 para que se ejecute automáticamente, incluso cada vez que reiniciemos nuestra máquina.
La forma de añadir un script de node a PM2 es escribir el siguiente comando:
pm2
Es el nombre del gestor de procesosstart
es el comando que indica a pm2 que vas a arrancar un procesoindex.js
es el fichero que queremos que arranque. Vale con otros comandos también.--name app
es el nombre que le damos al proceso, para identificarlo.
Al ejecutar dicho comando, obtendríamos una salida parecida a la siguiente:
$ pm2 start index.js --name app
[PM2] Starting /home/manz/node-examples/index.js in fork_mode (1 instance)
[PM2] Done.
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name │ mode │ R │ status │ cpu │ memory │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0 │ app │ fork │ 0 │ online │ 0% │ 5.7mb │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘
[PM2][WARN] Current process list is not synchronized with saved list.
Type 'pm2 save' to synchronize.
Observa que tras el mensaje de confirmación, aparece un panel que nos muestra todos los procesos añadidos a PM2 y sus características (si está activo, consumo de CPU, de memoria RAM, etc...). Recuerda que esta acción es temporal, si queremos guardar los cambios en PM2 y que sean permanentes, tienes que sincronizar los datos escribiendo pm2 save
:
$ pm2 save
A parte de estos, existen varios comandos que puedes utilizar para gestionar la lista de procesos: comprobar los procesos que existen en la lista, reiniciarlos, pararlos, eliminarlos, etc:
Comando | Descripción |
---|---|
pm2 start index.js --name app | Crea un nuevo proceso que ejecute index.js con nombre app . |
pm2 status | Muestra la lista de procesos en PM2. |
pm2 restart app | Reinicia el proceso (lo detiene y lo vuelve a arrancar). |
pm2 reload app | Recarga el proceso. Similar al anterior. |
pm2 stop app | Detiene el proceso y lo deja en la lista de PM2, pero detenido. |
pm2 delete app | Elimina el proceso de la lista de PM2. |
Puedes indicar
all
en lugar del nombre de la app si quieres realizar una acción en todos los procesos.
Revisar estado de los procesos
Al ejecutar procesos con PM2, la salida de estos comandos no aparece en nuestra terminal, por lo que puede que nos perdamos información importante. Para ver estos mensajes, basta con ejecutar el comando pm2 logs
. Observa que a la izquierda aparece el id
del proceso, seguido de |
y el nombre del proceso, para identificarlos.
Así, si tenemos varios procesos, sabemos que salida corresponde a cada uno:
$ pm2 logs
PM2 | 2024-07-02T20:39:10: PM2 log: App [app:0] online
0|app | Server running at http://localhost:4321/
Si lo que queremos es tener un panel de control donde aparezcan los logs y un panel de todos los procesos para ver los recursos usados, etc, podemos utilizar el comando pm2 monit
, que es un monitor de recursos:
$ pm2 monit
┌─ Process List ──────┐┌── app Logs ─────────────────────────────────────┐
│[ 0] app Mem: ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
└─────────────────────┘└───────────────────────────────────────────────────┘
┌─ Custom Metrics ────┐┌─ Metadata ────────────────────────────────────────┐
└─────────────────────┘└───────────────────────────────────────────────────┘
left/right: switch boards | up/down/mouse: scroll | Ctrl-C: exit To go
De hecho, este panel es interactivo y es un poco más sencillo para revisar y monitorizar los recursos y el estado de forma más cómoda.
Fichero de configuración
Por último, una buena idea sería poder utilizar PM2 de forma no interactiva, es decir, en lugar de ejecutar comandos, tenerlo todo guardado y automatizarlo. Para ello, podemos crear un archivo de configuración e indicar a PM2 que lea la información de ahí.
En primer lugar, creamos un fichero pm2.config.json
. Este fichero contendrá un objeto con la propiedad apps
, que a su vez contiene un array con todos los procesos que queremos que se ejecuten:
{
"apps": [
{
"name": "app",
"script": "index.js",
"env": {
"NODE_ENV": "production",
"HOST": "localhost",
"PORT": 3001
}
}
]
}
En su interior, con name
o script
podemos indicar los datos del proceso y en el campo env
guardar la información de las variables de entorno. Si lo deseas, puedes utilizar otros mecanismos para leer las variables de entorno de un fichero externo, pero PM2 tiene este sistema para evitar complicaciones.
Ahora, en nuestro código del fichero index.js
, añadimos unas lineas para obtener las variables de entorno. Simplemente importamos env
desde node:process
y, si queremos que sea más cómodo trabajar con estas variables por separado, desestructuramos env
en las variables que necesites:
import { env } from "node:process";
const { PORT, HOST } = env;
// ...
Una vez hechas estas modificaciones, podemos arrancar el fichero .json
creado. Esto leerá la estructura y creará los procesos definidos:
$ pm2 start pm2.config.json