كيفية إعداد بنية الخدمات المصغرة في Ruby: دليل خطوة بخطوة
نشرت: 2022-03-11ما هي الخدمات المصغرة؟
تعد الخدمات المصغرة واحدة من أحدث الاتجاهات في تصميم البرامج حيث تتواصل العديد من الخدمات المستقلة فيما بينها ولها عملياتها ومواردها الخاصة. يختلف هذا الأسلوب عن التصميم النموذجي لتطبيق خادم العميل. يتكون تطبيق خادم العميل المعتاد من عميل واحد أو أكثر ، ونهاية خلفية متجانسة تتضمن جميع بيانات المجال والمنطق ، وواجهة برمجة تطبيقات تتيح للعملاء الوصول إلى النهاية الخلفية ووظائفها.
في بنية الخدمات المصغرة ، يتم استبدال الواجهة الخلفية المتجانسة الموصوفة بمجموعة من الخدمات الموزعة. يسمح هذا التصميم بفصل المسؤوليات بشكل أفضل ، وسهولة الصيانة ، ومرونة أكبر في اختيار التقنيات لكل خدمة ، وسهولة التوسع والتسامح مع الأخطاء. في الوقت نفسه ، تواجه الأنظمة الموزعة المعقدة مجموعة تحدياتها. لديهم فرصة أكبر للتعامل مع ظروف السباق ، ويصعب تصحيحهم لأن المشكلات لا يتم تحديدها بسهولة في خدمة واحدة ، ولكن بدلاً من ذلك يتم توزيعها من خلال العديد. إذا لم يتم بذل جهد لاتباع أفضل الممارسات أثناء بناء مثل هذا النظام ، فقد تجد نفسك محاطًا بحرائق لا تعرف كيفية إخمادها. يجب توخي الحذر بشكل خاص مع عقود الحمولة النافعة للخدمات ، حيث قد تؤثر التغييرات في خدمة واحدة على جميع عملائها ، وبالتالي على كل مجموعة خدمات النهاية الخلفية.
كل هذه الاعتبارات مهمة ، لكن دعنا نفترض أنك فكرت فيها بالفعل. الآن ما تريده هو إيجاد طريقة لإنشاء خدمة مصغرة بنفسك. لذلك دعونا نتعمق في ذلك.
كيفية إعداد بنية الخدمات المصغرة
يوجد حاليًا العديد من الطرق التي يمكنك من خلالها إعداد الخدمات المصغرة الخاصة بك ، وسنركز في هذا الدليل على بنية الوسيط.
وسيط معماري
تعد بنية الوسيط إحدى الطرق التي يمكنك من خلالها توصيل خدماتك فيما بينها. في ذلك ، تحيط جميع الخدمات بخادم المراسلة والوسيط وكلها متصلة به. ترسل الخدمات رسائل إلى الوسيط ، الذي يعرف بعد ذلك الخدمة أو الخدمات الأخرى التي يحتاجها لإعادة توجيه هذه الرسائل. بهذه الطريقة ، لا تحتاج الخدمات إلى الاحتفاظ بمعلومات حول الخدمات الأخرى. بدلاً من ذلك ، يعتمدون على الوسيط للاهتمام بجميع الرسائل ، ويسمح لهم بالعزل والتركيز فقط على مجالهم الخاص. قد يقوم الوسيط أيضًا بتخزين الرسائل عندما تكون أجهزة الاستقبال الخاصة بهم معطلة ، مما يسمح للمرسلين والمستقبلين بعدم إجبارهم على العمل في نفس الوقت ، مما يسمح بعزل أكبر. بالطبع ، هناك عيوب في هذا الحل حيث يمكن للوسيط أن يصبح سريعًا عنق زجاجة نظرًا لأن جميع الاتصالات يجب أن تمر من خلالها ، ويمكن أن يصبح أيضًا نقطة فشل واحدة للواجهة الخلفية الخاصة بك. ومع ذلك ، هناك عدة طرق للتخفيف من هذه المشاكل. تتمثل إحدى الطرق في تشغيل مثيلات متعددة من الوسيط بالتوازي ، مما يسمح بتحمل أفضل لأخطاء النظام. طريقة أخرى هي استخدام معماريات أخرى. تختلف البنى البديلة عن البنية التي سننفذها في هذا الدليل من خلال عدم استخدام وسيط ، أو باستخدام بنية وسيط مختلفة ، أو باستخدام بروتوكول مراسلة مختلف مثل HTTP.
التواصل بين الخدمات
في هذا الدليل ، سنستخدم 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" إلى خدمة "الشخص".
هيكل الكود
لنبدأ بإلقاء نظرة على شجرة الكود الخاصة بالمشروع. تبدو هكذا:
- دليل
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.