Messaging -> PubSub in OTP

OTP steht für Open Telecom Platform ; So geschah es in der Vergangenheit, weil die Plattform für die Bedürfnisse und das Geld von Ericsson geschaffen wurde . Im Prinzip hat dieser Name jedoch ungefähr so ​​viele Konnotationen für seine Funktionalität wie Äpfel mit Telefonen von durchschnittlicher Qualität.


Das Hauptunterscheidungsmerkmal von OTP ist nach Angaben der Autoren die Fehlertoleranz. Kein Multithreading, kein Darstellermodell, keine umfangreichen Mustervergleichsfunktionen, nicht einmal transparentes Clustering und keine Hot-Code-Upgrades. Fehlertoleranz.


Die virtuelle Maschine von Erlang ist oberflächlich sehr einfach gestaltet: Es gibt eine Reihe von „Prozessen“ (nicht Systemprozesse, Erlang-Prozesse) mit isoliertem Speicher, die Nachrichten austauschen können. Das ist alles. Hier ist, was Joe Armstrong dazu sagte:


In meinem Blog habe ich argumentiert, dass Prozesse sich so ziemlich wie Menschen verhalten sollten. Die Menschen haben private Erinnerungen und tauschen Daten per Nachrichtenübermittlung aus.
- Warum ich Shared Memory nicht mag

Messaging in OTP ist sehr einfach: Ein Prozess sendet eine Nachricht synchron oder asynchron an einen anderen (oder eine Gruppe anderer Prozesse). Dazu müssen Sie jedoch wissen, an wen diese Nachrichten gesendet werden sollen. Das heißt, der Absender ist der Exchange Manager. Aber was ist, wenn wir nur eine Sendung senden und allen interessierten Prozessen ermöglichen möchten, diese Nachricht zu abonnieren?


Ja, dies ist ein normaler PubSub, aber in OTP ist er standardmäßig nicht implementiert. Nun, es spielt keine Rolle, wir haben alle Steine ​​in einer Stunde, um sie auf die Knie zu zwingen. Fangen wir an.


Implementierungsoptionen


Grundsätzlich enthält Elixir ein Registry , das als Gerüst für pubsub verwendet werden kann . Ein kleiner, selbst erstellter Code, eine saubere Betreuung aller Teilnehmer (ein Supervisor für alle) und fertig. Das einzige Problem ist, dass die Registry lokal ist und nicht weiß, wie man Cluster bildet. Das heißt, in einer verteilten Umgebung (verteilten Knoten) funktioniert diese Schönheit nicht.


Phoenix.PubSub gibt es eine verteilte Implementierung von Phoenix.PubSub , die mit zwei vorgefertigten Implementierungen geliefert wird: Phoenix.PubSub.PG2 und Phoenix.PubSub.Redis . Nun, Redis ist eindeutig ein zusätzliches Glied in unserer Kette, aber PG2 , das neben den Erlang-Gruppen von pg2 Prozessen arbeitet, ist es. Auch ohne Boilerplate geht das aber nicht.


Wir haben also alles, um bequeme PubSub- Abonnements in unserer Anwendung einzurichten . Ist es Zeit, einen Texteditor zu öffnen? - Nicht wirklich. Ich dupliziere nicht gerne Code von Projekt zu Projekt, und alles, was ich in einer Bibliothek isolieren kann, wird für die Wiederverwendung isoliert.


Envío


So wurde das Envío Paket geboren. Da Chatter, wie Sie wissen, keinen Cent wert ist, werden wir mit Anwendungsbeispielen beginnen.


Lokaler Newsletter → 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 

Das ist im Allgemeinen alles. Es bleibt MyApp.Sub in unseren Supervisor-Baum zu verschieben, und dieser Prozess beginnt, alle Nachrichten zu empfangen, die mit Funktionen von MyApp.Pub , die auch nicht mit Code überladen sind.


 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 

Verteilter Newsletter → PG2


Bei verteilten Systemen, die aus vielen Knoten bestehen, funktioniert diese Methode nicht. Wir müssen in der Lage sein, Nachrichten von anderen Knoten zu abonnieren, und Registry kein Assistent. Es gibt jedoch PG2 , das dasselbe behaviour implementiert.


 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 

Der einzige Unterschied zum obigen eigenständigen Code ist der Parameter manager: :phoenix_pub_sub , den wir an use Envio.Subscriber (und use Envio.Publisher ) übergeben, um ein Modul zu erstellen, das auf :pg2 anstelle der lokalen Registry basiert. Mit diesem Publisher gesendete Nachrichten sind jetzt auf allen Knoten im Cluster verfügbar.


Bewerbung


Envío unterstützt die sogenannten Backends . Envio.Slack wird mit der Envio.Slack mit der Sie das Senden von Nachrichten an Slack vereinfachen können. Alles, was für die Anwendung erforderlich ist - senden Sie eine Nachricht an den in der config/prod.exs konfigurierten Kanal - den Envío config/prod.exs Envío . Hier ist eine Beispielkonfiguration:


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

Jetzt werden alle Nachrichten, die durch Aufrufen von MyApp.Pub.publish(:slack, %{foo: :bar}) gesendet werden, an den entsprechenden Kanal in Slack gesendet, und zwar in einer MyApp.Pub.publish(:slack, %{foo: :bar}) Formatierung. Um das Senden von Nachrichten an Slack zu beenden, beenden Envio.Slack einfach den Envio.Slack Prozess. Weitere Beispiele (z. B. ein Login- IO ) finden Sie in Tests.


Warum kreuzige ich, versuche es selbst.


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

Gute kommunikation!

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


All Articles