nodejs: gestionnaires de processus et modules ES6

Dans le monde JavaScript côté serveur, je suis un débutant avec un esprit propre et presque épuré. Par conséquent, lorsque j'ai appris l'existence des gestionnaires de processus, et en particulier de pm2 , j'ai immédiatement essayé de l'utiliser pour exécuter un service backend simple sur nodejs à des fins d'auto-éducation. Je suis très impressionné par la possibilité de connecter des modules en code JS via import ( modules ES6 ), car il vous permet d'utiliser le même code à la fois dans le navigateur et côté serveur, et j'ai noté un service simple avec des modules ES6.


Bref, je n'ai pas réussi à lancer la version ES6 de l'application sous pm2 , il vaut mieux utiliser forever ou systemd pour exécuter de telles applications. Under the cut - un rapport sur les résultats pour ceux qui aiment les textes plus longtemps.


Présentation


Dans le cadre de cette publication, un gestionnaire de processus fait référence à un service dont la tâche principale est de surveiller une application nodejs cours d'exécution et de la redémarrer en cas de plantage. De plus, le gestionnaire de processus peut (mais n'est pas obligé) de collecter des informations sur les ressources consommées par l'application (processeur, mémoire).


Service de test


Pour tester les gestionnaires de processus, j'ai utilisé ce code dans le service ES6 ( github repo ):


 # 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!'); }); 

et dans le module ES6:


 # src/mod/es6.mjs export default { getName: function () { return "ES6 module is here."; } } 

Un service similaire effectué avec des modules CommonJS ressemble à ceci:


 # 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!"); }); 

Module CJS:


 # src/mod/cjs.js module.exports = { getName: function () { return "CommonJS module is here."; } }; 

Démarrage du service sans utiliser le gestionnaire de processus sur nodejs v12.14.0:


 $ node --experimental-modules ./src/app_es6.mjs # ES6-service $ node ./src/app_cjs.js # CJS-service 

pm2


pm2 est actuellement le leader parmi les gestionnaires de processus pour la fonctionnalité proposée (en plus de maintenir le processus en état de fonctionnement, il y a aussi le clustering , la surveillance de l'utilisation des ressources, diverses stratégies de redémarrage des processus).


Le service CJS démarre sans problème ( pm2 v4.2.1):


 $ pm2 start ./src/app_cjs.js -i 4 


le nombre spécifié d'instances de service dans le cluster est également pris en charge sans problème:


 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 

Après avoir tué une instance ( PID 29864 ), le gestionnaire de processus en a immédiatement récupéré une nouvelle ( 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 

Mais la version ES6 de l'application ne fonctionne pas correctement dans pm2 . Lors du passage de l' argument "--experimental-modules" à nodejs:


 $ pm2 start ./src/app_es6.mjs -i 4 --node-args="--experimental-modules" 

il se trouve cette image:


Dans les journaux, nous voyons:


 $ 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 

Autrement dit, pm2 ne peut pas exécuter de scripts utilisant des modules ES6 sans transpilation. Le dernier numéro sur ce sujet a été créé le 5 décembre 2019 (il y a environ un mois).


pour toujours


forever est le prochain gestionnaire de processus le plus populaire après pm2 ( npmtrends ). Il s'agit d'un projet plus ancien (démarré en 2010 contre 2013 pour pm2 ), mais il se concentre plus sur la fonctionnalité que pm2 . forever "affûté" pour maintenir constamment le processus sans aucun pm2 plus supplémentaire sous forme d'équilibrage de charge et de surveillance des ressources utilisées. À en juger par la fréquence des validations, le projet est dans un état stable (la phase de développement active est déjà passée) et vous ne pouvez pas en attendre de nouvelles fonctions. Je n'ai pas trouvé de moyen de passer des arguments à nodejs partir de la ligne de commande lors du démarrage forever , mais il existe une telle possibilité si vous utilisez le fichier de configuration:


 { "uid": "app_es6", "max": 5, "spinSleepTime": 1000, "minUptime": 1000, "append": true, "watch": false, "script": "src/app_es6.mjs", "command": "node --experimental-modules" } 

L'exécution de l'application dans cette version ressemble à ceci:


 $ 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 

Voici les processus eux-mêmes:


 $ 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 

Lorsque le processus est "tué" ( PID 3979 ), le gestionnaire en soulève régulièrement un nouveau ( 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 fait un excellent travail de lancement d'une application qui utilise des modules ES6, mais la question se pose, pourquoi tirer forever sur les systèmes linux si des fonctionnalités similaires peuvent être obtenues grâce aux propres ressources du système d'exploitation?


systemd


systemd vous permet de créer des services dans un environnement linux et de contrôler leur lancement, y compris en cas de crash brutal. Il suffit de créer un fichier-unité avec une description du service ( ./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 

et liez-le au répertoire /etc/systemd/system (les chemins doivent être absolus dans le fichier d'unité). L'option pour redémarrer le service en cas d'arrêt soudain est:


 Restart=always 

Le service est lancé comme suit:


 # 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! 

Lorsque le processus est "tué" ( PID 2184 ), systemd soulève régulièrement un nouveau ( 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 

Autrement dit, systemd fait la même chose que forever , mais à un niveau plus fondamental.


Strongloop


Lors de l'examen des options de mise en œuvre pour les gestionnaires de processus, StrongLoop apparaît souvent. Cependant, il semble bien que ce projet ait cessé de se développer (la dernière version 6.0.3 a été publiée il y a 3 ans ). Je n'ai même pas pu l'installer sur Ubuntu 18.04 via 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 

Grâce au yarn package a été installé, malgré le grand nombre de messages sur les versions obsolètes des dépendances et des erreurs d'installation, cependant, j'ai refusé d'étudier StronLoop.


Outils pour les développeurs


Très souvent à côté de pm2 et forever il existe des packages tels que nodemon , watch , onchange . Ces outils ne sont pas des gestionnaires de processus, mais ils vous permettent de surveiller les modifications des fichiers et d'exécuter les commandes associées à ces modifications (y compris le redémarrage de l'application).


Résumé


Un gestionnaire de processus comme pm2 est un service très utile dans le monde JS côté serveur. Mais, malheureusement, pm2 lui pm2 même pm2 permet pas d'exécuter des applications nodejs modernes (en particulier, avec des modules ES6). Comme je n'aime pas vraiment la transpilation, le gestionnaire de processus le plus acceptable dans nodejs pour le nodejs pour moi le systemd traditionnel (ou ses alternatives ). Cependant, je serai heureux d'utiliser pm2 dès que pm2 pourra prendre en charge des applications avec des modules ES6.

Source: https://habr.com/ru/post/fr482370/


All Articles