nodejs: Prozessmanager und ES6-Module

In der serverseitigen JavaScript-Welt bin ich ein Neuling mit einem klaren, fast übersichtlichen Verstand. Als ich von der Existenz von Prozessmanagern und speziell von pm2 erfuhr , versuchte ich sofort, damit einen einfachen nodejs Dienst auf nodejs zum Zwecke der Selbstausbildung nodejs . Ich bin sehr beeindruckt von der Möglichkeit, Module im JS-Code per import ( ES6-Module ) zu verbinden, weil Sie können damit denselben Code sowohl im Browser als auch auf der Serverseite verwenden, und ich habe einen einfachen Dienst mit ES6-Modulen aufgeschrieben.


Kurz pm2 , es ist mir nicht gelungen, die ES6-Version der Anwendung unter pm2 . Es ist besser, entweder forever oder systemd zu verwenden, um solche Anwendungen auszuführen. Under the cut - ein Bericht über die Ergebnisse für diejenigen, die Texte länger mögen.


Einleitung


Im Kontext dieser Publikation bezieht sich ein Prozessmanager auf einen Dienst, dessen Hauptaufgabe darin besteht, eine ausgeführte nodejs Anwendung zu überwachen und im Falle eines Absturzes neu zu starten. Außerdem kann (muss) der Prozessmanager Informationen zu den von der Anwendung verbrauchten Ressourcen (Prozessor, Speicher) sammeln.


Test-Service


Zum Testen von Prozessmanagern habe ich diesen Code im ES6-Service ( Github Repo ) verwendet:


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

und im ES6-Modul:


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

Ein ähnlicher Dienst, der mit CommonJS-Modulen ausgeführt wird, sieht folgendermaßen aus:


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

CJS-Modul:


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

Starten des Dienstes ohne Verwendung des Prozessmanagers auf nodejs v12.14.0:


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

pm2


pm2 ist pm2 führend unter den Prozessmanagern für die vorgeschlagene Funktionalität (neben der Aufrechterhaltung der Funktionsfähigkeit des Prozesses gibt es auch Clustering , Überwachung der Ressourcennutzung und verschiedene Strategien für den Neustart von Prozessen).


Der CJS-Dienst startet ohne Probleme ( pm2 v4.2.1):


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


Die angegebene Anzahl von Dienstinstanzen im Cluster wird ebenfalls problemlos unterstützt:


 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 

Nach dem PID 29864 einer Instanz ( PID 29864 ) nahm der Prozessmanager sofort eine neue auf ( 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 

Die ES6-Version der Anwendung funktioniert in pm2 jedoch nicht ordnungsgemäß. Wenn Sie das Argument "--experimental-modules" an nodejs übergeben:


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

es stellt sich dieses bild heraus:


In den Protokollen sehen wir:


 $ 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 

Das heißt, dass pm2 keine Skripte pm2 kann , die ES6-Module ohne Transpilation verwenden. Die neueste Ausgabe zu diesem Thema wurde am 5. Dezember 2019 (vor ungefähr einem Monat) erstellt.


für immer


forever ist nach pm2 ( npmtrends ) der am weitesten verbreitete Prozessmanager. Dies ist ein älteres Projekt (das 2010 gegen 2013 für pm2 ), aber es konzentriert sich enger auf die Funktionalität als pm2 . forever "geschärft", um den Prozess ohne zusätzliche pm2 Plus in Form von Lastausgleich und Überwachung der verwendeten Ressourcen ständig aufrechtzuerhalten. Gemessen an der Häufigkeit der Festschreibungen befindet sich das Projekt in einem stabilen Zustand (die aktive Entwicklungsphase ist bereits abgelaufen) und Sie können keine neuen Funktionen von ihm erwarten. Ich habe keine Möglichkeit gefunden, Argumente über die Befehlszeile an nodejs zu nodejs , wenn ich forever nodejs , aber es gibt eine solche Möglichkeit, wenn Sie die Konfigurationsdatei verwenden:


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

Das Ausführen der Anwendung in dieser Version sieht folgendermaßen aus:


 $ 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 

Hier sind die Prozesse selbst:


 $ 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 

Wenn der Prozess "beendet" wird ( PID 3979 ), löst der Manager regelmäßig einen neuen aus ( 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 ist ein ausgezeichneter Job beim Starten einer Anwendung, die ES6-Module verwendet. Es stellt sich jedoch die Frage, warum Linux-Systeme forever in Frage kommen, wenn ähnliche Funktionen über die eigenen Ressourcen des Betriebssystems erzielt werden können.


systemd


Mit systemd können Sie Dienste in einer Linux-Umgebung erstellen und deren Start steuern, auch im Falle eines plötzlichen Absturzes. Es reicht aus, eine Unit-Datei mit einer Beschreibung des Dienstes ( ./app_es6.service ) zu ./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 

und verknüpfen Sie es mit dem Verzeichnis /etc/systemd/system (Pfade müssen in der Unit-Datei absolut sein). Die Option zum Neustarten des Dienstes im Falle eines plötzlichen Stopps ist:


 Restart=always 

Der Dienst wird wie folgt gestartet:


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

Wenn der Prozess "beendet" wird ( PID 2184 ), löst systemd regelmäßig einen neuen aus ( 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 

Das heißt, systemd macht dasselbe wie forever , jedoch auf einer grundlegenderen Ebene.


Strongloop


Wenn Sie Implementierungsoptionen für Prozessmanager überprüfen, wird StrongLoop häufig angezeigt . Es sieht jedoch sehr danach aus, dass sich dieses Projekt nicht mehr weiterentwickelt (die neueste Version 6.0.3 wurde vor 3 Jahren veröffentlicht ). Ich konnte es nicht einmal auf Ubuntu 18.04 über npm installieren:


 # 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 

yarn Paket wurde über yarn installiert, obwohl es eine große Anzahl von Meldungen zu veralteten Versionen von Abhängigkeiten und Installationsfehlern gab. Ich lehnte es jedoch ab, StronLoop zu studieren.


Entwicklertools


Sehr oft neben pm2 und forever gibt es solche Pakete wie nodemon , watch , onchange . Diese Tools sind keine Prozessmanager, ermöglichen jedoch die Überwachung von Änderungen in Dateien und die Ausführung von Befehlen, die mit diesen Änderungen verknüpft sind (einschließlich des Neustarts der Anwendung).


Zusammenfassung


Ein Prozessmanager wie pm2 ist ein sehr nützlicher Dienst in der serverseitigen JS-Welt. Leider pm2 selbst nicht die Ausführung moderner nodejs Anwendungen (insbesondere mit ES6-Modulen). Da ich Transpilation nicht wirklich mag, ist der nodejs für mich akzeptabelste Prozessmanager in nodejs das traditionelle systemd (oder dessen Alternativen ). pm2 pm2 ich jedoch pm2 , sobald pm2 Anwendungen mit ES6-Modulen unterstützen kann.

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


All Articles