nodejs:流程管理器和ES6模块

在服务器端JavaScript领域,我是一个新手,头脑清晰,整洁。 因此,当我发现存在进程管理器,尤其是关于pm2时 ,我立即尝试使用它在nodejs上运行一些简单的后端服务, nodejs进行自我教育。 通过import以JS代码连接模块( ES6模块 )的能力给我留下了深刻的印象,因为 它允许您在浏览器和服务器端使用相同的代码,并且我写下了带有ES6模块的简单服务。


简而言之,我没有成功在pm2下启动应用程序的ES6版本,最好forever使用或使用systemd运行此类应用程序。 削减-为喜欢文本的人提供的结果报告。


引言


在本出版物的上下文中,进程管理器指的是一项服务,其主要任务是监视正在运行的nodejs应用程序,并在发生崩溃时重新启动它。 同样,进程管理器可以(但不必)收集有关应用程序(处理器,内存)消耗的资源的信息。


测试服务


对于测试流程经理,我在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!'); }); 

在ES6模块中:


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

CommonJS模块执行的类似服务如下所示:


 # 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模块:


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

在不使用nodejs v12.14.0上的进程管理器的情况下启动服务:


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

下午2


pm2当前是所提议功能的流程管理者中的领导者(除了使流程保持在工作状态之外,还包括集群 ,资源使用监视, 重启流程的各种策略 )。


CJS服务启动没有问题( pm2 v4.2.1):


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


还可以毫无问题地支持集群中指定数量的服务实例:


 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 

杀死一个实例( PID 29864 )之后,流程管理器立即选择一个新实例( 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 

但是该应用程序的ES6版本在pm2中无法正常工作。 当参数“ --experimental-modules”传递给nodejs时:


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

原来这张图:


在日志中,我们看到:


 $ 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 

也就是说,实际上, pm2不能运行未经ES6模块编译的脚本。 关于此主题的最新一于2019年12月5日创建(大约一个月前)。


永远


pm2npmtrends )之后, forever是第二受欢迎的流程管理器。 这是一个较旧的项目(从2010年开始于pm2于2013年启动),但与pm2 ,它对功能的关注范围更窄。 forever “变尖锐”,以不断维护过程,而无需任何额外的pm2 ,其形式为负载平衡和监视所使用的资源。 从提交的频率来看,该项目处于稳定状态(活动开发阶段已经过去),您不能期望它会有任何新功能。 我没有找到forever启动时从命令行将参数传递给nodejs的方法,但是如果您使用配置文件,则有这样的可能性:


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

在此版本中运行应用程序如下所示:


 $ 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 

以下是流程本身:


 $ 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 

当该过程被“ PID 3979 ”( PID 3979 )时,管理器会定期引发一个新的过程( 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不会对启动使用ES6模块的应用程序起到出色的作用,但问题是,如果可以通过操作系统自己的资源来实现类似的功能,为什么要在Linux系统上forever使用呢?


系统的


systemd允许您在linux环境中创建服务并控制它们的启动,包括在突然崩溃的情况下。 创建带有服务描述( ./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 

并将其链接到/etc/systemd/system目录(路径在单位文件中必须是绝对的)。 在突然停止的情况下重新启动服务的选项是:


 Restart=always 

服务启动如下:


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

当进程被“杀死”( PID 2184 )时, systemd定期引发一个新的过程( 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 

也就是说, systemdforever ,但在更基本的层面上。


强循环


在查看流程管理器的实施选项时, StrongLoop经常会弹出。 但是,这个项目似乎已经停止开发了( 3年之前发布了最新版本6.0.3)。 我什至无法通过npm在Ubuntu 18.04上安装它:


 # 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安装yarn软件包,但是,我拒绝研究StronLoop。


开发人员工具


经常在pm2旁边,并且forever 都有诸如nodemonwatchonchange之类的软件包。 这些工具不是过程管理器,但是它们使您可以监视文件中的更改并执行附加到这些更改的命令(包括重新启动应用程序)。


总结


pm2类的流程管理器在服务器端JS世界中是一项非常有用的服务。 但是,不幸的是, pm2本身不允许运行现代的nodejs应用程序(尤其是ES6模块)。 由于我真的不喜欢转译,因此nodejs对我而言, nodejsnodejs流程管理器是传统的systemd (或其替代品 )。 但是,只要pm2可以支持带有ES6模块的应用程序,我将很高兴使用pm2

Source: https://habr.com/ru/post/zh-CN482370/


All Articles