في عالم جافا سكريبت من جانب الخادم ، أنا مبتدئ بعقل نظيف ومرتب تقريبًا. لذلك ، عندما اكتشفت وجود مديري العمليات ، وبالتحديد عن pm2 ، حاولت على الفور استخدامها لتشغيل خدمة خلفية بسيطة على nodejs
لغرض التعليم الذاتي. أنا معجب جدًا بالقدرة على توصيل الوحدات النمطية في رمز JS عبر import
( وحدات ES6 ) ، لأن يسمح لك باستخدام نفس الكود في المتصفح وعلى جانب الخادم ، وقد كتبت خدمة بسيطة مع وحدات ES6.
باختصار ، لم تنجح في تشغيل إصدار ES6 من التطبيق تحت pm2
، فمن الأفضل استخدام إما 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
PM2
pm2
هو 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
. عند تمرير الوسيطة "- وحدات تجريبية" إلى 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 دون transpilation. تم إنشاء الإصدار الأخير من هذا الموضوع في 5 كانون الأول (ديسمبر) 2019 (قبل شهر تقريبًا).
إلى الأبد
forever
هو مدير العمليات الأكثر شعبية بعد pm2
( npmtrends ). هذا هو مشروع قديم (بدأ في عام 2010 في عام 2013 مقابل pm2
) ، لكنه يركز بشكل أضيق على الوظيفة مقارنة pm2
. forever
"شحذ" للحفاظ على العملية باستمرار دون أي إضافات pm2
في شكل موازنة التحميل ومراقبة الموارد المستخدمة. وفقًا لتكرار الالتزامات ، فإن المشروع في حالة مستقرة (لقد مرت مرحلة التطوير النشط بالفعل) ولا يمكنك توقع أي وظائف جديدة منه. لم أجد طريقة لتمرير الوسائط إلى nodejs
من سطر الأوامر عند بدء التشغيل forever
، ولكن هناك مثل هذا الاحتمال إذا كنت تستخدم ملف التكوين:
{ "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 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
directory (يجب أن تكون المسارات مطلقة في ملف الوحدة). خيار إعادة تشغيل الخدمة في حالة التوقف المفاجئ هو:
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
وهذا هو ، systemd
يفعل نفس الشيء إلى forever
، ولكن على مستوى أكثر أساسية.
StrongLoop
عند مراجعة خيارات التنفيذ لمديري العمليات ، غالبًا ما تظهر شاشة StrongLoop . ومع ذلك ، يبدو أن هذا المشروع قد توقف عن التطوير (تم إصدار أحدث إصدار 6.0.3 قبل 3 سنوات ). لم أتمكن حتى من تثبيته على Ubuntu 18.04 عبر 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
من خلال yarn
تم تثبيت الحزمة ، على الرغم من العدد الكبير من الرسائل حول الإصدارات المهملة من التبعيات وأخطاء التثبيت ، ومع ذلك ، فقد رفضت دراسة StronLoop.
أدوات المطور
في كثير من الأحيان بجانب pm2
وإلى forever
هناك مجموعات مثل nodemon ، watch ، onchange . هذه الأدوات ليست من مديري العمليات ، ولكنها تسمح لك بمراقبة التغييرات في الملفات وتنفيذ الأوامر المرتبطة بهذه التغييرات (بما في ذلك إعادة تشغيل التطبيق).
ملخص
يعد مدير العمليات مثل pm2
خدمة مفيدة للغاية في عالم JS من جانب الخادم. ولكن لسوء الحظ ، pm2
يسمح pm2
نفسه بتشغيل تطبيقات nodejs
الحديثة (على وجه الخصوص ، مع وحدات ES6). نظرًا لأنني لا أحب الترجمة ، فإن مدير العمليات الأكثر قبولًا في nodejs
في nodejs
بالنسبة لي هو النظام التقليدي (أو بدائله ). ومع ذلك ، سأكون سعيدًا لاستخدام pm2
بمجرد أن يدعم pm2 التطبيقات بوحدات ES6.