كيفية إعداد بنية الخدمات المصغرة في Ruby: دليل خطوة بخطوة

نشرت: 2022-03-11

ما هي الخدمات المصغرة؟

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

تحل الخدمات المصغرة محل الخوادم الخلفية المتجانسة الكلاسيكية
سقسقة

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

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

كيفية إعداد بنية الخدمات المصغرة

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

وسيط معماري

بنية الوسيط ، مع وسيط (B) في المنتصف ، وأربع خدمات صغيرة تحيط به ، قم بتسميتها N ، S ، E ، W. يبدأ مسار الطلب / الاستجابة عند إدخال خارج العمارة ، ثم يتبع المسار N ، B ، E ، B ، S ، B ، W ، B ، E ، B ، N ، قبل الخروج أخيرًا كمخرج.

تعد بنية الوسيط إحدى الطرق التي يمكنك من خلالها توصيل خدماتك فيما بينها
سقسقة

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

التواصل بين الخدمات

في هذا الدليل ، سنستخدم ZeroMQ للتعامل مع الاتصال بين الخدمات والوسيط.

مكدس ZeroMQ. في الأعلى يوجد قالب به علامة حذف ثم علامة ZeroMQ. تحتوي الكتلة السفلية ، من أعلى إلى أسفل: على النقل والشبكة ورابط البيانات والمادي.

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

بناء مجموعة الخدمات المصغرة

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

لذا ، فلنبدأ في البناء.

ابدء

أولاً ، دعنا نتأكد من أن لديك كل ما تحتاجه لتشغيل الوسيط والخدمة. أولاً ، ابدأ بتنزيل وتثبيت Node.js و ZeroMQ و Git على جهازك. إذا كنت تستخدم OSX ، فهناك حزم البيرة لكل منها ، ومعظم توزيعات Linux بها حزمة لكل منها أيضًا ، لذلك لن تواجه مشكلة في ذلك. يمكن لمستخدمي Windows ببساطة استخدام روابط التنزيل المتوفرة أعلاه.

تشغيل الوسيط

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

لذلك ، أولاً ، استخدم الأمر Git التالي لتنزيل المشروع على جهازك:

 $ git clone [email protected]:dadah/zmq-broker-bootstrap.git

بعد القيام بذلك ، انتقل إلى الدليل الذي تم إنشاؤه:

 $ cd zmq-broker-bootstrap

الآن قم بتثبيت تبعيات الحزمة:

 $ npm install

الوسيط جاهز الآن. لتشغيل الوسيط الخاص بك ، قم بتشغيل الأمر التالي:

 $ bin/zss-broker run

يمكنك العثور على ملفات التكوين لكل بيئة في الدليل config/ . هذا هو تكوين التطوير الافتراضي:

 { "broker": { "backend": "tcp://127.0.0.1:7776", "frontend": "tcp://127.0.0.1:7777" }, "log": { "consolePlugin": { "level": "debug" } } }

تحدد معلمة backend ip:port للواجهة الخلفية والواجهة الأمامية للوسيط. عنوان النهاية الخلفية هو المكان الذي يتلقى فيه الوسيط الطلبات والردود على الخدمات ، ويكون عنوان الواجهة الأمامية هو المكان الذي يتلقى فيه عملاء الخدمة ويرسلونه إليهم. يمكنك أيضًا ضبط مستوى التسجيل عن طريق تغيير log.consolePlugin.level . القيم المحتملة هي trace ، debug ، info ، warn error ، وهي تحدد مقدار معلومات التسجيل التي ستخرجها عملية الوسيط.

تشغيل الخدمة

بعد أن تحصل على وسيطك ، حان الوقت لتطوير أول خدمة صغيرة من Ruby. ابدأ بفتح نافذة وحدة تحكم جديدة. بعد ذلك ، قم بإنشاء دليل حيث سيتم تخزين خدماتك ، ثم انتقل إلى هذا الدليل. في هذا الدليل ، نستخدم عميل Ruby وخدمة ZMQ SOA Suite. هناك خدمة تمهيدية "Hello world" متاحة ، لذلك دعونا نستخدمها لتشغيل أول خدمة مصغرة لنا.

انتقل إلى دليل الخدمات الخاص بك وقم باستنساخ مستودع التمهيد:

 $ git clone [email protected]:dadah/zmq-service-suite-ruby-bootstrap.git

انتقل إلى الدليل الذي تم إنشاؤه حديثًا:

 $ cd zmq-service-suite-ruby-bootstrap

الآن قم بتثبيت جميع التبعيات:

 $ bundle install

لبدء الخدمة ، قم بتشغيل الأمر التالي:

 $ bin/zss-service run

رائعة. لديك خدمتك الأولى قيد التشغيل.

إذا انتقلت إلى نافذة وحدة التحكم حيث تركت وسيطك قيد التشغيل ، يمكنك رؤية الإخراج التالي:

 2015-12-15 16:45:05 | INFO | BROKER - Async Broker is waiting for messages... 2015-12-15 16:45:14 | DEBUG | BACKEND - received from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 76f50741-913a-43b9-94b0-36d8f7bd75b1 2015-12-15 16:45:14 | DEBUG | BACKEND - routing from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 76f50741-913a-43b9-94b0-36d8f7bd75b1 to SMI.UP request... 2015-12-15 16:45:14 | INFO | SMI - SMI register for sid: HELLO-WORD instance: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b! 2015-12-15 16:45:14 | DEBUG | BACKEND - reply to: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 76f50741-913a-43b9-94b0-36d8f7bd75b1 with status: 200 2015-12-15 16:45:15 | DEBUG | BACKEND - received from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 3b3a0416-73fa-4fd2-9306-dad18bc0502a 2015-12-15 16:45:15 | DEBUG | BACKEND - routing from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 3b3a0416-73fa-4fd2-9306-dad18bc0502a to SMI.HEARTBEAT request... 2015-12-15 16:45:15 | DEBUG | BACKEND - reply to: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 3b3a0416-73fa-4fd2-9306-dad18bc0502a with status: 200 2015-12-15 16:45:16 | DEBUG | BACKEND - received from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: b3044c24-c823-4394-8204-1e872f30e909 2015-12-15 16:45:16 | DEBUG | BACKEND - routing from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: b3044c24-c823-4394-8204-1e872f30e909 to SMI.HEARTBEAT request... 2015-12-15 16:45:16 | DEBUG | BACKEND - reply to: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: b3044c24-c823-4394-8204-1e872f30e909 with status: 200

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

تستهلك من الخدمة

الآن لدينا خدمة قيد التشغيل ، كيف نستخدمها؟

في مستودع التمهيد ، يوجد عميل وهمي يمكنك استخدامه لاختبار خدمة "Hello World" الخاصة بك. ما عليك سوى فتح نافذة أو علامة تبويب وحدة تحكم جديدة ، وانتقل إلى دليل الخدمة الخاص بك. بمجرد أن تكون هناك ، قم بتشغيل الأمر التالي:

 $ bin/zss-client

يجب أن نرى شيئا من هذا القبيل:

 15-49-15 16:49:54 | INFO | ZSS::CLIENT - Request 90a88081-3485-45b6-91b3-b0609d64592a sent to HELLO-WORD:*#HELLO/WORLD with 1.0s timeout 15-49-15 16:49:54 | INFO | ZSS::CLIENT - Received response to 90a88081-3485-45b6-91b3-b0609d64592a with status 200 "Hello World"

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

 Started hello-word daemon... 15-45-15 16:45:14 | INFO | ZSS::SERVICE - Starting SID: 'HELLO-WORD' ID: 'hello-word#aaa65374-8585-410a-a41d-c8a5b024553b' Env: 'development' Broker: 'tcp://127.0.0.1:7776' 15-49-15 16:49:54 | INFO | ZSS::SERVICE - Handle request for HELLO-WORD:*#HELLO/WORLD 15-49-15 16:49:54 | INFO | ZSS::SERVICE - Reply with status: 200

جيد. لقد أطلقت للتو واستهلكت خدمتك المصغرة "Hello World". لكن هذا ليس ما شرعنا في القيام به. نريد بناء خدمتنا (خدماتنا). دعنا نصل إليها ، إذن.

بناء خدمتك

أولاً ، دعنا نوقف خدمة "Hello World". انتقل إلى نافذة وحدة التحكم بالخدمة واضغط على Ctrl+C لإيقاف الخدمة. بعد ذلك ، نحتاج إلى تحويل خدمة "Hello World" إلى خدمة "الشخص".

هيكل الكود

لنبدأ بإلقاء نظرة على شجرة الكود الخاصة بالمشروع. تبدو هكذا:

التسلسل الهرمي للملف / المجلد لمشروع مثالنا zmq-service-suite-ruby-bootstrap. تم وصفه بالتفصيل أدناه ، ولكن لاحظ أن آخر ثلاثة ملفات .rb المذكورة هي في الواقع ضمن lib / repositories ، وليس ضمن lib نفسه.

  • دليل bin هو المكان الذي تخزن فيه البرامج النصية التي تطلق خدمتك.
  • يخزن دليل config جميع ملفات التكوين.
    • ملف boot.rb هو المكان الذي يمكنك فيه إضافة جميع تبعيات الخدمة الخاصة بك. إذا فتحته ، يمكنك ملاحظة وجود العديد من التبعيات المدرجة بالفعل هناك. إذا كنت بحاجة إلى إضافة المزيد ، فهذا هو المكان الذي يجب عليك القيام به.
    • يخزن ملف application.yml جميع إعدادات التطبيق الخاصة بك. سوف نلقي نظرة على هذا الملف لاحقا.
    • في دليل config/initializers ، يمكنك إضافة سكربتات التهيئة. يمكنك ، على سبيل المثال ، إضافة إعدادات لاتصالات ActiveRecord أو Redis هنا. سيتم تشغيل البرامج النصية التي تضيفها إلى هذا الدليل عند بدء تشغيل الخدمة.
  • في دليل db/migrate ، يمكنك تخزين عمليات ترحيل ActiveRecord أو Sequel إذا كان لديك أي منها. في حالة عدم قيامك بذلك ، يمكنك حذف هذا الدليل تمامًا.
  • دليل lib هو المكان الذي يوجد فيه رمز التطبيق الرئيسي الخاص بك.
    • يقوم ملف settings.rb ببساطة بتحميل ملف application.yml وإتاحته في جميع أنحاء نطاق الخدمة ، بحيث يمكنك الوصول إلى التكوينات الخاصة بك في أي مكان. على سبيل المثال ، يقوم Settings.broker.backend بإرجاع عنوان الواجهة الخلفية للوسيط الذي حددته في ملف YML أعلاه.
    • ملف service_register.rb هو المكان الذي تسجل فيه خدماتك ومسارات خدمتك. سوف نشرح ذلك لاحقا.
    • يحدد ملف hello_world_service.rb نقاط نهاية خدمة "Hello World".
    • دليل lib/daos هو المكان الذي تخزن فيه كائنات ActiveModel الخاصة بك إذا كنت تستخدم ActiveRecord ، أو أي كائنات أخرى للوصول إلى البيانات قد تنشئها في النهاية ، مثل طرازات Sequel.
    • يخزن الدليل lib/dtos كائنات نقل البيانات الخاصة بك. هذه الكائنات هي التي يتم إرسالها في النهاية إلى عملاء الخدمة.
    • يخزن دليل lib/repositories مستودعاتك. المستودعات هي كائنات تسمح للخدمات بالوصول إلى البيانات وهي الكائنات الوحيدة المسموح لها بمعالجة DAOs. لذلك إذا كانت الخدمة تريد مجموعة من مثيلات "Hello World" ، فسوف تطلب من المستودع الخاص بها. يستخدم المستودع بدوره أدوات DAOs المناسبة لجلب البيانات ذات الصلة من قاعدة البيانات. يتم بعد ذلك تعيين البيانات في مجموعة DTO أو مجموعة DTO "HelloWorld" أو "HelloWorld" والتي يتم إرجاعها إلى الخدمة.
    • دليل lib/repositories/mappers هو المكان الذي تخزن فيه رسامي الخرائط. رسامو الخرائط عبارة عن كائنات تقوم بتحويل DAOs إلى DTOs والعكس صحيح.

يبدو ملف application.yml من دليل config كما يلي:

 defaults: &defaults broker: backend: tcp://127.0.0.1:7776 frontend: tcp://127.0.0.1:7777 logging: console: level: info development: <<: *defaults test: <<: *defaults production: <<: *defaults

يعيّن هذا الإعداد ببساطة عنوان الواجهة الخلفية والواجهة الأمامية للوسيط ومستوى التسجيل.

إذا كان كل هذا يبدو محيرًا حتى الآن ، فلا تقلق لأنه سيصبح أكثر وضوحًا ونحن نمضي قدمًا.

خدمة "شخص"

لذا ، دعنا نواصل خدمة "الشخص". لنبدأ بتكوين اتصال قاعدة البيانات. افتح الملف config/initializers/active_record.rb وأزل التعليق عن السطر الوحيد هناك. بعد ذلك ، أضف الإدخال التالي إلى تكوين التطوير الخاص بك في application.yml بحيث يبدو كالتالي:

 defaults: &defaults broker: backend: tcp://127.0.0.1:7776 frontend: tcp://127.0.0.1:7777 logging: console: level: info database: adapter: postgresql database: zss-tutorial-development

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

 $ rake db:create

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

التالي هو الهجرة. لذلك ، ما عليك سوى إنشاء الملف db/migrate migrate المسمى 000_creates_persons.rb :

 $ touch db/migrate/000_creates_persons_table.rb

افتح الملف وأنشئ الترحيل كما تفعل مع ترحيل ريلز العادي:

 class CreatesPersons < ActiveRecord::Migration def change create_table :persons do |t| t.name t.timestamps end end end

بعد ذلك ، قم بتشغيله:

 $ rake db:migrate == 0 CreatesPersons: migrating ================================================ -- create_table(:persons) DEPRECATION WARNING: `#timestamp` was called without specifying an option for `null`. In Rails 5, this behavior will change to `null: false`. You should manually specify `null: true` to prevent the behavior of your existing migrations from changing. (called from block in change at /Users/francisco/Code/microservices-tutorial/db/migrate/000_creates_persons.rb:6) -> 0.0012s == 0 CreatesPersons: migrated (0.0013s) =======================================

الآن وقد قمنا بإنشاء طاولتنا ، فلنقم بإنشاء نموذج لها. قم بإنشاء ملف lib/daos/person.rb :

 $ touch lib/daos/person.rb

قم بتحريره على هذا النحو:

 module DAO class Person < ActiveRecord::Base end end

هذا هو النموذج الخاص بك. أنت الآن بحاجة إلى إنشاء نموذج DTO لـ "الشخص" بحيث يمكنك إعادته إلى العميل. قم بإنشاء ملف lib/dtos/person.rb :

 $ touch lib/dtos/person.rb

قم بتحريره على هذا النحو:

 module DTO class Person < Base attr_reader :id, :name end end

بعد ذلك ، عليك إنشاء مخطط لتحويل "الشخص" DAO إلى DTO "شخص". قم بإنشاء ملف lib/repositories/mappers/person.rb ، وقم بتحريره على النحو التالي:

 module Mapper class Person < Mapper::Base def self.to_dao dto_instance DAO::Person.new id: dto_instance.id, name: dto_instance.name end def self.to_dto dao_instance DTO::Person.new id: dao_instance.id, name: dao_instance.name end end end

هنا ، يتطلب منك Mapper::Base تنفيذ self.to_dao و self.to_dto . إذا كنت لا ترغب في القيام بذلك ، يمكنك تطبيق self.map بدلاً من ذلك وتجاوز Mapper::Base.map الذي يستدعي to_dao أو to_dto ، اعتمادًا على ما إذا كانت السمة التي يتلقاها هي DAO أو DTO.

الآن لديك DAO للوصول إلى قاعدة البيانات الخاصة بك ، و DTO لإرسالها إلى العميل ، و Mapper لتحويل أحدهما إلى الآخر. يمكنك الآن استخدام هذه الفئات الثلاث داخل المستودع لإنشاء منطق يمكّنك من الحصول على أشخاص من قاعدة البيانات وإرجاع مجموعة مقابلة من DTOs.

فلنقم بإنشاء المستودع إذن. قم بإنشاء ملف lib/repositories/person.rb :

 $ touch lib/dtos/person.rb

قم بتحريره على هذا النحو:

 module Repository class Person < Repository::Base def get DAO::Person.all.map do |person| Mapper::Person.map(person) end end end end

يحتوي هذا المستودع فقط على طريقة المثيل التي get على جميع الأشخاص من قاعدة البيانات وتعيينهم في مجموعة من DTOs للأشخاص - بسيط جدًا. دعونا نجمع كل هذا معًا الآن. كل ما تبقى الآن هو إنشاء الخدمة ونقطة النهاية التي تستدعي هذا المستودع. للقيام بذلك ، دعنا ننشئ الملف lib/person_service.rb :

 $ touch lib/person_service.rb

قم بتحريره على هذا النحو:

 class PersonService < BaseService attr_reader :person_repo def initialize @person_repo = Repository::Person.new end def get payload, headers persons = person_repo.get() if persons.empty? raise ZSS::Error.new(404, "No people here") else persons.map &:serialize end end end

تقوم خدمة "الشخص" بتهيئة المستودع في مُهيئته. تحتوي جميع طرق المثيل العامة لخدمة "الشخص" على حمولة ورؤوس يمكنك حذفها إذا لم تكن بحاجة إليها. كلاهما Hashie::Mash بتخزين المتغيرات المرسلة إلى نقطة النهاية ، إما كسمات أو رؤوس ، وتحاكي ردودهما استجابات HTTP لأن كل استجابة لها رمز حالة يمكن للعملاء استخدامه لمعرفة نتيجة الطلبات المرسلة إلى الخدمة ، جنبًا إلى جنب مع حمولة استجابة الخدمة. أكواد الاستجابة هي نفسها التي تتوقعها من خادم HTTP. على سبيل المثال ، سيرجع الطلب الناجح رمز الحالة 200 ، جنبًا إلى جنب مع حمولة الاستجابة. في حالة حدوث خطأ في الخدمة ، سيكون رمز الحالة 500 ، وإذا كان هناك خطأ ما في المعلمات المرسلة إلى الخادم ، فسيكون رمز الحالة 400. يمكن للخدمة الرد مع معظم رموز حالة HTTP مع حمولتها. لذلك ، على سبيل المثال ، إذا كنت تريد أن تخبر خدمتك عملائها عندما لا يُسمح لهم بالوصول إلى نقطة نهاية معينة ، فيمكنك القيام بذلك عن طريق الرد برمز 403. يمكنك مشاهدة مثال آخر لرموز الاستجابة إذا نظرت إلى رمز الخدمة أعلاه. في نقطة النهاية get ، نعيد رمز الحالة 404 جنبًا إلى جنب مع الرسالة الاختيارية "لا يوجد أشخاص هنا" عندما لا يتم العثور على أشخاص ، تمامًا مثل خادم HTTP سيعيد 404 إذا لم تكن هناك موارد متاحة. إذا كان المستودع يعيد الأشخاص بالفعل ، فإن الخدمة تسلسل DTOs وتعيدهم إلى العميل. يحتوي كل DTO على مُسلسل افتراضي يقوم بإرجاع كائن JSON بالمفاتيح والقيم المقابلة المحددة إما attr_reader أو attr_accessible في تعريف DTO. يمكنك بالطبع تجاوز المسلسل عن طريق تحديد طريقة التسلسل في فئات DTO الخاصة بك.

الآن بعد أن تم تحديد الخدمة ، نحتاج إلى تسجيلها. هذه هي الخطوة النهائية. افتح الملف lib/service_register.rb واستبدل جميع تكرارات "HelloWorld" بـ "الشخص" ، بحيث يبدو الملف أخيرًا إلى حد ما مثل هذا:

 module ZSS class ServiceRegister def self.get_service config = Hashie::Mash.new( backend: Settings.broker.backend ) service = ZSS::Service.new(:person, config) personInstance = PersonService.new service.add_route(personInstance, :get) return service end end end

كما لاحظت على الأرجح ، هناك تغيير بسيط في استدعاء add_route . أزلنا السلسلة "HELLO / WORLD". وذلك لأن السلسلة مطلوبة فقط إذا كان فعل الخدمة لا يتطابق مع الطريقة التي تنفذها. في حالتنا ، عند استدعاء خدمة الشخص بفعل GET ، فإن الطريقة المراد استدعاؤها هي get ، حتى نتمكن من حذف السلسلة.

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

 config = Hashie::Mash.new( backend: Settings.broker.backend ) service = ZSS::Service.new(:person, config)

ثم يقوم بإنشاء مثيل لمعالج الخدمة:

 personInstance = PersonService.new

بعد ذلك ، يكون معالج الخدمة مرتبطًا بالخدمة:

 service.add_route(personInstance, :get)

أخيرًا ، يجب أن يُرجع مثيل الخدمة.

 return service

الآن ، هناك خطوة واحدة أخيرة قبل أن نتمكن من إطلاق خدمة "الشخص" ؛ نحن بحاجة إلى إنشاء برنامج نصي قابل للتنفيذ لذلك. لدينا بالفعل واحدة من أجل "HelloService". لذا ، افتح ملف bin/zss-service ، واستبدل "hello-word" بـ "person" ، واحفظ الملف. ارجع إلى وحدة التحكم وقم بتشغيل:

 $ bin/zss-service run Starting person: PID: ./log LOGS: ./log Started person daemon... 15-29-15 19:29:54 | INFO | ZSS::SERVICE - Starting SID: 'PERSON' ID: 'person#d3ca7e1f-e229-4502-ac2d-0c01d8c285f8' Env: 'development' Broker: 'tcp://127.0.0.1:7776'

هذا هو. لقد بدأت للتو خدمة "الشخص" لأول مرة. الآن دعونا نختبرها. افتح ملف bin/zss-client ، وقم بتغيير متغير sid إلى "شخص" وقم بتغيير استدعاء العميل من hello_world() get() . بمجرد الانتهاء من ذلك ، قم بتشغيل العميل في نافذة جديدة:

 $ bin/zss-client /Users/francisco/.rvm/gems/ruby-2.1.2/gems/zss-0.3.4/lib/zss/client.rb:41:in `new': No people here (ZSS::Error) from /Users/francisco/.rvm/gems/ruby-2.1.2/gems/zss-0.3.4/lib/zss/client.rb:41:in `call' from /Users/francisco/.rvm/gems/ruby-2.1.2/gems/zss-0.3.4/lib/zss/client.rb:55:in `method_missing' from bin/zss-client:12:in `<main>'

كما ترى ، لقد ZSS::Error . هذا لأننا نرفع خطأ عندما لا يتم العثور على أشخاص بواسطة الخدمة وليس لدينا أشخاص حتى الآن في قاعدة بيانات خدمتنا.

دعونا نتعامل مع هذا الخطأ بعد ذلك. افتح zss-client وقم بتحريره كما يلي:

 begin client = ZSS::Client.new(sid, config) p client.get() rescue ZSS::Client => e if e.code == 404 p e.message else raise e end end

نقوم الآن بطباعة رسالة الخطأ عندما يكون رمز الخطأ هو 404 ، مع رفع الخطأ إذا كان مختلفًا. دعنا نرى ذلك أثناء العمل من خلال تشغيل عميلنا مرة أخرى:

 $ bin/zss-client "No people here"

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

 $ rake service:console

أضف بعض الأشخاص:

 $ rake service:console [1] pry(main)> DAO::Person.create name: 'John' => #<DAO::Person:0x007fe51bbe9d00 id: 1, name: "John", created_at: 2015-12-16 13:22:37 UTC, updated_at: 2015-12-16 13:22:37 UTC> [2] pry(main)> DAO::Person.create name: 'Mary' => #<DAO::Person:0x007fe51c1dafe8 id: 2, name: "Mary", created_at: 2015-12-16 13:22:42 UTC, updated_at: 2015-12-16 13:22:42 UTC> [3] pry(main)> DAO::Person.create name: 'Francis' => #<DAO::Person:0x007fe51bc11698 id: 3, name: "Francis", created_at: 2015-12-16 13:22:53 UTC, updated_at: 2015-12-16 13:22:53 UTC> [4] pry(main)> exit

الآن ، قم بتشغيل العميل الخاص بك مرة أخرى.

 $ bin/zss-client [{"id"=>1, "name"=>"John"}, {"id"=>2, "name"=>"Mary"}, {"id"=>3, "name"=>"Francis"}]

ها أنت ذا.

الاعتبارات النهائية

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

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

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

آمل أن يساعدك هذا في البدء في الخدمات المصغرة. إذا كنت ترغب في التحقق من رمز الخدمة ، يتوفر إصدار كامل على GitHub.