En el mundo de JavaScript del lado del servidor, soy un novato con una mente limpia, casi despejada. Por lo tanto, cuando me enteré de la existencia de administradores de procesos, y específicamente sobre pm2 , inmediatamente traté de usarlo para ejecutar algún servicio de backend simple en nodejs
con el propósito de autoeducarme. Estoy muy impresionado con la capacidad de conectar módulos en código JS mediante import
( módulos ES6 ), porque le permite usar el mismo código tanto en el navegador como en el lado del servidor, y escribí un servicio simple con módulos ES6.
En resumen, no logré lanzar la versión ES6 de la aplicación en pm2
, es mejor usarla forever
o systemd
para ejecutar dichas aplicaciones. Debajo del corte: un informe sobre los resultados para aquellos a quienes les gustan los textos por más tiempo.
Introduccion
En el contexto de esta publicación, un administrador de procesos se refiere a un servicio cuya tarea principal es monitorear una aplicación nodejs
ejecución y reiniciarla en caso de un bloqueo. Además, el administrador de procesos puede (pero no tiene que) recopilar información sobre los recursos consumidos por la aplicación (procesador, memoria).
Servicio de prueba
Para probar los administradores de procesos, utilicé este código en el servicio ES6 ( repositorio github ):
# src/app_es6.mjs import express from "express"; import mod from "./mod/es6.mjs"; const app = express(); const msg = "Hello World! " + mod.getName(); app.get("/", function (req, res) { console.log(msg); res.send(msg); }); app.listen(3000, function () { console.log('ES6 app listening on port 3000!'); });
y en el módulo ES6:
# src/mod/es6.mjs export default { getName: function () { return "ES6 module is here."; } }
Un servicio similar realizado con módulos CommonJS se ve así:
# src/app_cjs.js const express = require("express"); const mod = require("./mod/cjs.js"); const app = express(); const msg = "Hello World! " + mod.getName(); app.get("/", function (req, res) { console.log(msg); res.send(msg); }); app.listen(3000, function () { console.log("CommonJS app listening on port 3000!"); });
Módulo CJS:
# src/mod/cjs.js module.exports = { getName: function () { return "CommonJS module is here."; } };
Iniciar el servicio sin usar el administrador de procesos en nodejs
v12.14.0:
$ node --experimental-modules ./src/app_es6.mjs # ES6-service $ node ./src/app_cjs.js # CJS-service
pm2
pm2
es actualmente el líder entre los gerentes de procesos para la funcionalidad propuesta (además de mantener el proceso en condiciones de trabajo, también hay agrupación , monitoreo del uso de recursos, diversas estrategias para reiniciar procesos).
El servicio CJS se inicia sin problemas ( pm2
v4.2.1):
$ pm2 start ./src/app_cjs.js -i 4

El número especificado de instancias de servicio en el clúster también es compatible sin problemas:
root@omen17:~# ps -Af | grep app_cjs alex 29848 29828 0 15:31 ? 00:00:00 node /.../src/app_cjs.js alex 29855 29828 0 15:31 ? 00:00:00 node /.../src/app_cjs.js alex 29864 29828 0 15:31 ? 00:00:00 node /.../src/app_cjs.js alex 29875 29828 0 15:31 ? 00:00:00 node /.../src/app_cjs.js
Después de eliminar una instancia ( PID 29864
), el administrador de procesos inmediatamente recogió una nueva ( PID 30703
):
root@omen17:~# kill -s SIGKILL 29864 root@omen17:~# ps -Af | grep app_cjs alex 29848 29828 0 15:31 ? 00:00:00 node /.../src/app_cjs.js alex 29855 29828 0 15:31 ? 00:00:00 node /.../src/app_cjs.js alex 29875 29828 0 15:31 ? 00:00:00 node /.../src/app_cjs.js alex 30703 29828 7 15:35 ? 00:00:00 node /.../src/app_cjs.js
Pero la versión ES6 de la aplicación no funciona correctamente en pm2
. Al pasar el argumento "--experimental-modules" a nodejs:
$ pm2 start ./src/app_es6.mjs -i 4 --node-args="--experimental-modules"
Resulta esta imagen:

En los registros vemos:
$ pm2 log ... /home/alex/.pm2/logs/app-es6-error-2.log last 15 lines: 2|app_es6 | at /usr/lib/node_modules/pm2/node_modules/async/internal/onlyOnce.js:12:16 2|app_es6 | at WriteStream.<anonymous> (/usr/lib/node_modules/pm2/lib/Utility.js:186:13) 2|app_es6 | at WriteStream.emit (events.js:210:5) 2|app_es6 | at internal/fs/streams.js:299:10 2|app_es6 | Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/alex/work/sof_es6_pm/src/app_es6.mjs 2|app_es6 | at Object.Module._extensions..mjs (internal/modules/cjs/loader.js:1029:9) 2|app_es6 | at Module.load (internal/modules/cjs/loader.js:815:32) 2|app_es6 | at Function.Module._load (internal/modules/cjs/loader.js:727:14) 2|app_es6 | at /usr/lib/node_modules/pm2/lib/ProcessContainer.js:297:23 2|app_es6 | at wrapper (/usr/lib/node_modules/pm2/node_modules/async/internal/once.js:12:16) 2|app_es6 | at next (/usr/lib/node_modules/pm2/node_modules/async/waterfall.js:96:20) 2|app_es6 | at /usr/lib/node_modules/pm2/node_modules/async/internal/onlyOnce.js:12:16 2|app_es6 | at WriteStream.<anonymous> (/usr/lib/node_modules/pm2/lib/Utility.js:186:13) 2|app_es6 | at WriteStream.emit (events.js:210:5) 2|app_es6 | at internal/fs/streams.js:299:10
Es decir, de hecho, pm2
no puede ejecutar scripts que usan módulos ES6 sin transpilación. El último número sobre este tema se creó el 5 de diciembre de 2019 (hace aproximadamente un mes).
por siempre
forever
es el siguiente administrador de procesos más popular después de pm2
( npmtrends ). Este es un proyecto más antiguo (comenzó en 2010 contra 2013 para pm2
), pero tiene un enfoque más pm2
en la funcionalidad que pm2
. "agudizado" para mantener constantemente el proceso sin ningún pm2
adicional de pm2
en forma de equilibrio de carga y monitoreo de los recursos utilizados. A juzgar por la frecuencia de las confirmaciones, el proyecto se encuentra en un estado estable (la fase de desarrollo activo ya ha pasado) y no puede esperar ninguna función nueva. No encontré una manera de pasar argumentos a nodejs
desde la línea de comando cuando comencé forever
, pero existe la posibilidad si usa el archivo de configuración:
{ "uid": "app_es6", "max": 5, "spinSleepTime": 1000, "minUptime": 1000, "append": true, "watch": false, "script": "src/app_es6.mjs", "command": "node --experimental-modules" }
La ejecución de la aplicación en esta versión se ve así:
$ forever start forever.es6.json ... $ forever list info: Forever processes running data: uid command script forever pid id logfile uptime data: [0] app_es6 node --experimental-modules src/app_es6.mjs 3972 3979 /home/ubuntu/.forever/app_es6.log 0:0:0:3.354
Aquí están los procesos en sí mismos:
$ ps -Af | grep es6 ubuntu 3972 1 0 12:01 ? 00:00:00 /usr/bin/node /usr/lib/node_modules/forever/bin/monitor src/app_es6.mjs ubuntu 3979 3972 0 12:01 ? 00:00:00 node --experimental-modules /home/ubuntu/sof_es6_pm/src/app_es6.mjs
Cuando el proceso es "cancelado" ( PID 3979
), el gerente regularmente plantea uno nuevo ( PID 4013
):
$ kill -s SIGKILL 3979 ubuntu@vsf:~/sof_es6_pm$ ps -Af | grep es6 ubuntu 3972 1 0 12:01 ? 00:00:00 /usr/bin/node /usr/lib/node_modules/forever/bin/monitor src/app_es6.mjs ubuntu 4013 3972 4 12:10 ? 00:00:00 node --experimental-modules /home/ubuntu/sof_es6_pm/src/app_es6.mjs
forever
hace un excelente trabajo al lanzar una aplicación que utiliza módulos ES6, pero surge la pregunta, ¿por qué utilizar forever
sistemas Linux si se puede lograr una funcionalidad similar a través de los propios recursos del sistema operativo?
systemd
systemd le permite crear servicios en un entorno Linux y controlar su lanzamiento, incluso en el caso de un bloqueo repentino. Es suficiente crear un archivo de unidad con una descripción del servicio ( ./app_es6.service
):
[Unit] Description=Simple web server with ES6 modules. After=network.target [Service] Type=simple Restart=always PIDFile=/run/app_es6.pid WorkingDirectory=/home/ubuntu/sof_es6_pm ExecStart=/usr/bin/nodejs --experimental-modules /home/ubuntu/sof_es6_pm/src/app_es6.mjs [Install] WantedBy=multi-user.target
y /etc/systemd/system
directorio /etc/systemd/system
(las rutas deben ser absolutas en el archivo de la unidad). La opción para reiniciar el servicio en caso de una parada repentina es:
Restart=always
El servicio se lanza de la siguiente manera:
# systemctl start app_es6.service # systemctl status app_es6.service ● app_es6.service - Simple web server with ES6 modules. Loaded: loaded (/home/ubuntu/sof_es6_pm/app_es6.service; linked; vendor preset: enabled) Active: active (running) since Thu 2020-01-02 11:09:42 UTC; 9s ago Main PID: 2184 (nodejs) Tasks: 11 (limit: 4662) CGroup: /system.slice/app_es6.service └─2184 /usr/bin/nodejs --experimental-modules /home/ubuntu/sof_es6_pm/src/app_es6.mjs Jan 02 11:09:42 vsf systemd[1]: Started Simple web server with ES6 modules.. Jan 02 11:09:42 vsf nodejs[2184]: (node:2184) ExperimentalWarning: The ESM module loader is experimental. Jan 02 11:09:42 vsf nodejs[2184]: ES6 app listening on port 3000!
Cuando se "mata" el proceso ( PID 2184
), systemd
genera regularmente uno nuevo ( PID 2233
):
# ps -Af | grep app_es6 root 2184 1 0 11:09 ? 00:00:00 /usr/bin/nodejs --experimental-modules /home/ubuntu/sof_es6_pm/src/app_es6.mjs # kill -s SIGKILL 2184 # ps -Af | grep app_es6 root 2233 1 3 11:10 ? 00:00:00 /usr/bin/nodejs --experimental-modules /home/ubuntu/sof_es6_pm/src/app_es6.mjs
Es decir, systemd
hace lo mismo que forever
, pero en un nivel más fundamental.
Strongloop
Al revisar las opciones de implementación para los administradores de procesos, StrongLoop a menudo aparece. Sin embargo, parece que este proyecto ha dejado de desarrollarse (la última versión 6.0.3 se lanzó hace 3 años ). npm
siquiera pude instalarlo en Ubuntu 18.04 a través de npm
:
# npm install -g strongloop npm WARN deprecated swagger-ui@2.2.10: No longer maintained, please upgrade to swagger-ui@3. ... npm ERR! A complete log of this run can be found in: npm ERR! /root/.npm/_logs/2020-01-02T11_25_15_473Z-debug.log
A través de yarn
se instaló yarn
paquete, a pesar de la gran cantidad de mensajes sobre versiones obsoletas de dependencias y errores de instalación, sin embargo, me negué a estudiar StronLoop.
Herramientas para desarrolladores
Muy a menudo al lado de pm2
y forever
hay paquetes como nodemon , watch , onchange . Estas herramientas no son administradores de procesos, pero le permiten monitorear los cambios en los archivos y ejecutar comandos adjuntos a estos cambios (incluido el reinicio de la aplicación).
Resumen
Un administrador de procesos como pm2
es un servicio muy útil en el mundo JS del lado del servidor. Pero, desafortunadamente, pm2
sí mismo no permite ejecutar aplicaciones modernas de nodejs
(en particular, con módulos ES6). Como realmente no me gusta la transpilación, el administrador de procesos más aceptable en nodejs
en este nodejs
para mí es el systemd
tradicional (o sus alternativas ). Sin embargo, estaré encantado de usar pm2
tan pronto como pm2
pueda admitir aplicaciones con módulos ES6.