node.js خوادم - العمل على البق. الجزء الأول

مساء الخير

هذه المقالة موجهة إلى المطورين المطلعين على node.js.

قمت مؤخرًا بتحضير مواد عن حقائق مفيدة لمطوري البرامج تحت node.js في مكتبنا. المشاريع التي نعمل عليها هي خدمات واجهة برمجة التطبيقات التي تستخدم وحدة node.js السريعة كخادم ويب. تعتمد المادة على الحالات الحقيقية التي كان يعمل فيها الرمز بشكل غير صحيح أو تم إخفاء المنطق فيه بعناية ، أو أثار أخطاء أثناء التوسيع. وبناءً على هذه المادة ، تم عقد ورشة عمل لتطوير الموظفين.

لذا ، قررت المشاركة. حتى الآن ، الجزء الأول فقط حوالي 30٪. إذا كانت مهتمة ، سوف تستمر!

حاولت توفير فرصة للتعرف السريع ، لذلك أخفيت الأمثلة والأسباب والتعليقات في المفسدين. إذا كانت العبارات واضحة ، يمكنك تخطي "الماء". على الرغم من أن "أشعل النار" في المفسدين يمكن أن تكون مثيرة للاهتمام أيضًا.

سألني أحد الزملاء خلال الندوة سؤالًا ، لماذا نتحدث عنه ، إذا كان كل شيء موجودًا بالفعل في هذه الوثائق أو تلك. جوابي كان كالتالي على الرغم من حقيقة أن الرسالة صحيحة ، كل شيء موجود بالفعل في التوثيق ، ما زلنا نرتكب أخطاء مزعجة تتعلق بسوء الفهم أو الجهل بالأشياء الأساسية.

لنبدأ!

الجهاز الظاهري Node.js



خيوط واحدة



على عكس javavm ، nodejs-vm هو خيوط مفردة ** .



المصدر

المزيد من التفاصيل
في نفس الوقت ، هناك مجموعة من الخيوط المساعدة التي يستخدمها الجهاز الظاهري نفسه ، على سبيل المثال ، لتنظيم الإدخال / الإخراج. ولكن يتم تنفيذ كافة التعليمات البرمجية للمستخدم في مؤشر ترابط "رئيسي" واحد فقط.

هذا يبسط الحياة إلى حد كبير ، حيث لا توجد منافسة. لا يمكن مقاطعة تنفيذ القانون في مكان تعسفي ومواصلته في مكان آخر. يتم تنفيذ الكود ببساطة حتى تكون هناك حاجة لانتظار شيء ما ، على سبيل المثال ، جاهزية البيانات عند القراءة من ملف. أثناء الانتظار ، قد يتم تنفيذ معالج آخر ، إما حتى ينتهي العمل ، أو حتى يبدأ أيضًا في الانتظار لشيء ما.

أي إذا كان هناك هيكل بيانات داخلي ، فلا داعي للقلق بشأن مزامنة الوصول إليه!

ماذا تفعل إذا لم يكن لدى الخيط "الرئيسي" الوقت الكافي لمعالجة البيانات؟

يتم القياس من خلال بدء عملية node.js أخرى أو ، إذا كانت موارد الخادم تقترب من نهايتها ، عن طريق بدء خادم آخر.

العواقب و "أشعلتنا"
كل شيء واضح هنا أيضًا. يجب أن تكون مستعدًا دائمًا لحقيقة أنه يمكن أن يكون هناك (وعلى الأرجح سيكون) أكثر من عملية node.js واحدة. وأحيانًا يمكن أن يكون هناك أيضًا عدة خوادم.

تم العثور على "أشعل النار" التي كانت مخبأة في التعليمات البرمجية لدينا


تتقاطع الخطوط المتوازية عند اللانهاية. من المستحيل إثبات ذلك ، لكني رأيت.
جان إيفل "رواية آدم وحواء".
جرت محاولة للتأكد من تفرد مثيلات الكيان في قاعدة البيانات حصريًا بواسطة التطبيق. بشكل عام ، هذا وبمعزل عن السياق لا يبدو سيئًا جدًا ، ولكن في هذه الحالة أكثر من ذلك. بدون إشراك خدمة طرف ثالث ، يبدو لي أن هذه المهمة ليس لها حل.

الزميل الذي شارك في هذا ، أراد حقًا تنفيذ هذا دون تضمين قاعدة البيانات الفعلية. في النهاية ، بعد بعض "المقاربات تجاه المقذوف" ، تم إدراكها ... من خلال إشراك SharePoint.


** Multithreading أو "إذا كنت تريد حقًا"



بدءًا من الإصدار 10.5.0 ، يتمتع node.js بدعم تجريبي لتعدد مؤشرات الترابط .


المصدر

لكن النموذج يبقى على حاله
  • ينشئ كل سير عمل جديد مثيله المعزول الخاص لبيئة عقدة الجهاز الظاهري.
  • تفتقر سير العمل إلى البيانات المشتركة القابلة للتغيير. (هناك زوجان من التحفظات ، ولكن في الأساس البيان عادل.)
  • يتم الاتصال باستخدام الرسائل و SharedArrayBuffer.

لذلك ، سيستمر الرمز القديم في العمل عند استخدام مهام سير العمل.
اقرأ المزيد هنا.


دورة حياة التطبيق



قلب nodejs-vm هو حلقة الأحداث. عندما يجب تعليق تنفيذ الكود أو يبدو أن الكود قد انتهى ، يمر التحكم إليه.

النص المخفي
تتحقق حلقة الأحداث مما إذا كانت (oh) الأحداث التي قمنا بتسجيل المعالجات لها قد حدثت أم لا. إذا حدث شيء ما ، فسيتم استدعاء المعالجات. وإذا لم يكن الأمر كذلك ، فسيتم التحقق مما إذا كان هناك أي "مولدين" للأحداث التي قمنا بتسجيل معالجات لها. يمكن أن يكون اتصال tcp مفتوح أو مؤقت مثل هذه المولدات. إذا لم يتم العثور عليهم ، فسيتم إنهاء البرنامج. خلاف ذلك ، من المتوقع حدوث أحد هذه الأحداث ، ويتم استدعاء المعالجات ، ويتكرر كل شيء.

نتيجة هذا السلوك هو حقيقة أنه عندما يبدو أن الكود قد انتهى ، لا يحدث الخروج من nodejs-vm ، على سبيل المثال ، لأننا سجلنا معالج مؤقت ، والذي يجب استدعاؤه بعد مرور بعض الوقت.

يظهر هذا في المثال التالي.

console.log('registering timer callbacks'); setTimeout( function() { console.log('Timer Event 1'); }, 1000); console.log('Is it the end?'); 


النتيجة:
 registering timer callbacks Is it the end? Timer Event 1 


اقرأ المزيد هنا.

آخر "أشعل النار" في رمزنا



يمكن لأي شخص إدارة الدولة!
تم تخزين علامة ما إذا كان المستخدم مسؤولاً في متغير عام. تمت تهيئة هذا المتغير على خطأ في بداية البرنامج. في وقت لاحق ، عندما سجل المسؤول ، تم تعيين هذا المتغير إلى true.

ونتيجة لذلك ، إذا قام المسؤول بزيارة النظام ، فسيتم اعتبار أي مستخدم قام بالوصول إلى هذا المثيل من الخدمة كمسؤول.

كلفني بعض الجهد لإظهار زميلي أن هناك خطأ في المنطق. كان الزميل على يقين من أنه يتم إنشاء بيئة جديدة تمامًا لكل طلب http.


package.json - الحقول التي تستحق التعبئة



package.json هو ملف الوصف لحزمتنا. في هذا السياق ، يتعلق الأمر بتطبيقنا ، وليس حول التبعيات. الحقول والتفسيرات المدرجة أدناه هي السبب في أنه يستحق ملؤها كل نفس.

النص المخفي

الاسم


حتى يتم نشر الحزمة في المستودع ، يمكن أيضًا تسجيل الحقل أيضًا. السؤال هو أن هذا الحقل مناسب للاستخدام لتسمية ملف التثبيت أو ، على سبيل المثال ، لعرض اسم المنتج على صفحة الويب الخاصة به. بشكل عام ، "ماذا تسمي اليخت ، .."

الإصدار


الفكرة الرئيسية هي عدم نسيان زيادة رقم الإصدار أثناء توسيع الوظائف ، وإصلاح الأخطاء ، ... لسوء الحظ ، لا يزال بإمكانك في مكتبنا العثور على المنتجات ذات الإصدار غير المتغير 0.0.0. ثم خمن أي نوع من الوظائف يعمل للعميل ...

الرئيسية


يوضح هذا الحقل الملف الذي سيتم تشغيله عند بدء تطبيقنا (`npm start`). إذا تم استخدام الحزمة كاعتماد ، فعندئذٍ سيتم استيراد الملف عند استخدام الوحدة الخاصة بنا بواسطة تطبيق آخر. الدليل الحالي هو الدليل حيث يوجد ملف `package.json`.

وأيضًا ، إذا استخدمنا ، على سبيل المثال ، vscode ، فسيتم تشغيل الملف المحدد في هذا الحقل عندما يتم استدعاء المصحح أو عند تشغيل الأمر "تنفيذ".

قد يتم حذف الملحق ".js". بل هي نتيجة لجميع حالات الاستخدام الممكنة ، لذلك لم يتم توضيحها مباشرة في الوثائق.

المحركات


يحتوي هذا الحقل على المجموعة: {"node": version ، "npm": version ، ...}.

أنا أعرف حقلي "العقدة" و "npm". إنها تحدد إصدارات node.js و npm اللازمة لتطبيقنا للعمل. يتم التحقق من الإصدارات بتشغيل الأمر npm install.

الصيغة القياسية لتحديد إصدارات حزم التبعية مدعومة: بدون البادئة (نسخة واحدة) ، البادئة "~" (يجب أن يتطابق أول رقمين من الإصدار) والبادئة "^" (يجب أن يتطابق فقط الرقم الأول من الإصدار). إذا كانت هناك بادئة ، فيجب أن يكون الإصدار أكبر من أو يساوي ذلك المحدد في هذا الحقل. مجرد قائمة الإصدارات ؛ إشارة صريحة أكثر ، أقل ، ... إلخ. يعمل أيضا.

تنويه يتحقق "تثبيت Npm" من الإصدارات المحددة في "المحركات" فقط في حالة تمكين الوضع "صارم على المحرك". نقوم بتضمينه لكل مشروع ، مع إضافة ملف. npmrc مع السطر: "engine-صارم = صحيح". ذات مرة ، "npm install" قام بهذا الاختيار بشكل افتراضي.

بعض الحاويات ، على الأقل في الوثائق ، تكتب أن الإصدارات المناسبة سيتم استخدامها بشكل افتراضي. في هذه الحالة ، نحن نتحدث عن Azure.

مثال:
 "engines": { "node": "~8.11", // require node version 8.11.* starting from 8.11.0 "npm": "^6.0.1" // require npm version 6.* starting from 6.0.1 }, 


أشعل النار العادي



والملك عارية!

تم الاتفاق مع العميل بشكل متكرر على أن الإصدار المطلوب من "node.js" يجب أن يكون على الأقل 8. عندما تم تسليم الإصدارات الأولية من التطبيق ، عمل كل شيء. "يوم واحد" بعد تسليم الإصدار الجديد على العميل ، توقف تشغيل التطبيق. كل شيء يعمل في اختباراتنا.

كانت المشكلة أنه في هذا الإصدار بدأنا في استخدام الوظائف التي كانت مدعومة فقط من الإصدار 8 node.js. لم يتم ملء حقل "المحركات" ، لذلك لم يلاحظ أحد من قبل أن العميل لديه نسخة قديمة من node.js. (خدمات الويب Azure الافتراضية).

مخطوطات


يحتوي الحقل على مجموعة من النموذج: {"script1": script1 ، "script2": script2 ، ...}.

هناك نصوص قياسية تعمل في حالة معينة. على سبيل المثال ، سيتم تنفيذ البرنامج النصي "تثبيت" بعد تشغيل "تثبيت npm". من الملائم للغاية ، على سبيل المثال ، التحقق من توفر البرامج اللازمة للتطبيق للعمل. أو ، على سبيل المثال ، لضغط جميع الملفات الثابتة المتاحة من خلال خدمة الويب الخاصة بنا حتى لا تضغط عليها بسرعة.

في هذه الحالة ، لا يمكنك أن تقتصر فقط على الأسماء القياسية. من أجل تنفيذ برنامج نصي عشوائي ، تحتاج إلى تشغيل "npm run script-name ".

من السهل جمع جميع النصوص المستخدمة في مكان واحد.

مثال:
  "scripts": { "install": "node scripts/install-extras", "start": "node src/well/hidden/main/server extra_param_1 extra_param_2", "another-script": "node scripts/another-script" } 


ملاحظة: يمكن حذف الامتداد ".js" في معظم الحالات.


package-lock.json - يساعد على تثبيت إصدارات معينة من التبعيات ، وليس أحدثها



النص المخفي
هل هي بوابة أم لا؟ ..


ظهر هذا الملف في npm مؤخرًا نسبيًا. الغرض منه هو تنظيم التكرار للتجميع.

وواحد آخر "أشعل النار"


لكني لم أغير أي شيء في برنامجي! عملت أمس!


على جهاز الأقران ، عمل التطبيق بشكل رائع. على جهاز كمبيوتر آخر في بيئة مماثلة ، في تطبيق تم وضعه من git إلى دليل جديد ، بعد تنفيذ "تثبيت npm" ، ظهرت أخطاء npm start حتى الآن.

كانت المشكلة ناتجة عن حقيقة أن الملف 'package-lock.json' مفقود من مستودع git. لذلك ، أثناء تثبيت الحزم ، تم تثبيت جميع تبعيات المستويات الثانية أو أكثر (بشكل طبيعي ، لم تتم كتابتها في package.json) على أحدث وجه ممكن. على كمبيوتر زميل ، كان كل شيء على ما يرام. تم تحديد مجموعة إصدارات غير متوافقة على جهاز الكمبيوتر الذي تم اختباره.

package-lock.json - إلى بوابة!



العودة من الاستطراد. يحتوي ملف "package-lock.json" على قائمة بجميع الوحدات المثبتة محليًا لتطبيقنا. يسمح لك وجود هذا الملف بإعادة إنشاء مجموعة من واحد إلى واحد من إصدارات الوحدات.

ملخّص: لا تنسَ وضع git وإدراجه في ملف التسليم (التثبيت) الخاص بالتطبيق!

مفيد: إذا كان الملف "package-lock.json" مفقودًا ، ولكن يوجد دليل "node_modules" مع جميع الوحدات اللازمة ، يمكن إعادة إنشاء الملف "package-lock.json":
 npm shrinkwrap rename npm-shrinkwrap.json package-lock.json 



يمكنك وضع حد لهذا الآن. المعلومات غير المدرجة هي تقنية تبسيط الكود التي يستخدمها فريقنا.

إذا تم الكشف عن أخطاء ، سأحاول إصلاحها بسرعة!

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


All Articles