المراسلة -> PubSub داخل OTP

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


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


الجهاز الظاهري Erlang المثبت على السطح بسيط للغاية في الهيكل: هناك مجموعة من "العمليات" (وليس عمليات النظام ، وعمليات Erlang) مع ذاكرة معزولة يمكنها تبادل الرسائل. هذا كل شيء. إليكم ما قاله جو أرمسترونغ حول هذا:


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

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


نعم ، هذه عبارة عن PubSub عادي ، لكن خارج نطاق التطبيق في OTP ، لم يتم تنفيذها. حسنًا ، لا يهم ، لدينا كل الطوب في ساعة واحدة لنركعها. لنبدأ.


خيارات التنفيذ


في الأساس ، يشتمل Elixir على وحدة نمطية Registry يمكن استخدامها كسقالة لحانة pubsub . رمز homespun قليلاً ، وإلقاء نظرة أنيق على جميع المشاركين (مشرف للجميع) ، ولقد انتهيت. المشكلة الوحيدة هي أن Registry محلي ولا يعرف كيفية التجميع. وهذا هو ، في بيئة موزعة (العقد الموزعة) هذا الجمال لن يعمل.


Phoenix.PubSub لنا ، هناك تطبيق موزع لـ Phoenix.PubSub ، والذي يأتي مع تطبيقين جاهزين: Phoenix.PubSub.PG2 و Phoenix.PubSub.Redis . حسنًا ، تعتبر PG2 رابطًا إضافيًا في PG2 ، ولكن PG2 ، التي تعمل على رأس مجموعات Erlang لعمليات pg2 ، هي كذلك. أيضا ، ومع ذلك ، دون boilerplate لن تفعل.


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


Envío


وهكذا ولدت حزمة Envío . بما أن الثرثرة ، كما تعلم ، لا يستحق فلساً واحداً ، فسنبدأ مع أمثلة الاستخدام.


النشرة المحلية → Registry


 defmodule MyApp.Sub do use Envio.Subscriber, channels: [{MyApp.Pub, :main}] def handle_envio(message, state) do # optionally call the default implementation {:noreply, state} = super(message, state) # handle it! IO.inspect({message, state}, label: "Received") # respond with `{:noreply, state}` as by contract {:noreply, state} end end 

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


 defmodule MyApp.Pub do use Envio.Publisher, channel: :main def publish(channel, what), do: broadcast(channel, what) def publish(what), do: broadcast(what) # send to :main end 

النشرة الموزعة → PG2


بالنسبة للأنظمة الموزعة التي تتكون من العديد من العقد ، لن تعمل هذه الطريقة. نحن بحاجة إلى أن نكون قادرين على الاشتراك في رسائل من العقد الأخرى ، Registry ليس مساعدًا هنا. ولكن هناك PG2 الذي ينفذ نفس behaviour .


 defmodule Pg2Sucker do use Envio.Subscriber, channels: ["main"], manager: :phoenix_pub_sub def handle_envio(message, state) do {:noreply, state} = super(message, state) IO.inspect({message, state}, label: "Received") {:noreply, state} end end 

الاختلاف الوحيد من الكود المستقل أعلاه هو المعلمة manager: :phoenix_pub_sub ، والتي use Envio.Subscriber ( use Envio.Publisher ) لإنشاء وحدة نمطية تستند إلى :pg2 بدلاً من Registry المحلي. الآن الرسائل المرسلة باستخدام هذا Publisher ستكون متاحة على جميع العقد في الكتلة.


تطبيق


Envío يدعم ما يسمى الخلفية . يأتي Envio.Slack مع Envio.Slack ، والذي يتيح لك تبسيط إرسال الرسائل إلى Slack . كل ما هو مطلوب من التطبيق - إرسال رسالة إلى القناة التي تم تكوينها في config/prod.exs - سوف يقوم config/prod.exs Envío . هنا مثال التكوين:


 config :envio, :backends, %{ Envio.Slack => %{ {MyApp.Pub, :slack} => [ hook_url: {:system, "SLACK_ENVIO_HOOK_URL"} ] } } 

الآن سيتم تسليم جميع الرسائل المرسلة عن طريق الاتصال بـ MyApp.Pub.publish(:slack, %{foo: :bar}) إلى القناة المقابلة في Slack ، مهيأة بشكل جميل. من أجل إيقاف إرسال الرسائل إلى Slack ، ما Envio.Slack سوى إيقاف عملية Envio.Slack . يمكن العثور على مزيد من الأمثلة (على سبيل المثال ، سجل في IO ) في الاختبارات.


لماذا أنا المصلوب ، حاول ذلك بنفسك.


 def deps do [ {:envio, "~> 0.8"} ] end 

التواصل الجيد!

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


All Articles