Messagerie -> PubSub dans OTP

OTP signifie Open Telecom Platform ; donc c'est arrivé historiquement, parce que la plateforme a été créée pour les besoins et pour l'argent d' Ericsson . Mais, en principe, ce nom a à peu près autant de connotations avec sa fonctionnalité que les pommes avec des téléphones de qualité moyenne.


Selon les auteurs, la principale caractéristique distinctive de l' OTP est la tolérance aux pannes. Pas de multithreading, pas de modèle d'acteur, pas de fonctionnalités riches de correspondance de modèles, pas même de clustering transparent et pas de mises à jour de code à chaud. Tolérance aux pannes.


La machine virtuelle Erlang montée en surface est très simple dans sa structure: il existe un tas de «processus» (pas les processus système, les processus Erlang) avec une mémoire isolée qui peuvent échanger des messages. C’est tout. Voici ce que Joe Armstrong a dit à ce sujet:


Dans mon blog, j'ai soutenu que les processus devraient se comporter à peu près comme les gens. Les gens ont des souvenirs privés et échangent des données en passant des messages.
- Pourquoi je n'aime pas la mémoire partagée

La messagerie à l'intérieur d'OTP est très simple: un processus envoie un message à un autre (ou à un groupe d'autres processus), de manière synchrone ou asynchrone. Mais pour cela, vous devez savoir à qui envoyer ces messages. Autrement dit, l'expéditeur est le gestionnaire d'échange. Mais que se passe-t-il si nous voulons simplement envoyer une diffusion et permettre à tous les processus intéressés de s'abonner à ce message?


Oui, c'est un PubSub régulier, mais hors de la boîte dans OTP il n'est pas implémenté. Eh bien, peu importe, nous avons toutes les briques en une heure pour le mettre à genoux. Commençons.


Options d'implémentation


Fondamentalement, Elixir comprend un module de Registry qui peut être utilisé comme échafaudage pour pubsub . Un petit code homepun, un regard soigné sur tous les participants (un superviseur pour tout le monde), et vous avez terminé. Le seul problème est que le Registry local et ne sait pas comment se mettre en cluster. Autrement dit, dans un environnement distribué (nœuds distribués), cette beauté ne fonctionnera pas.


Phoenix.PubSub nous, il existe une implémentation distribuée de Phoenix.PubSub , qui vient avec deux implémentations prêtes à l'emploi: Phoenix.PubSub.PG2 et Phoenix.PubSub.Redis . Eh bien, Redis est clairement un maillon supplémentaire dans notre chaîne, mais PG2 , qui travaille en plus des groupes Erlang de processus pg2 , l'est. En outre, cependant, sans passe-partout ne suffira pas.


Nous avons donc tout pour établir des abonnements PubSub pratiques dans notre application. Est-il temps d'ouvrir un éditeur de texte? "Pas vraiment." Je n'aime pas dupliquer le code d'un projet à l'autre, et tout ce que je peux isoler dans une bibliothèque est isolé pour être réutilisé.


Envío


Ainsi est né le paquet Envío . Comme le bavardage, comme vous le savez, ne vaut pas un sou, nous allons commencer par des exemples d'utilisation.


Bulletin local → 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 

C'est, en général, tout. Il reste à MyApp.Sub dans notre arborescence de superviseur, et ce processus commencera à recevoir tous les messages envoyés à l'aide des fonctions de MyApp.Pub , qui n'est pas non plus surchargé de code.


 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 

Newsletter distribuée → PG2


Pour les systèmes distribués composés de nombreux nœuds, cette méthode ne fonctionnera pas. Nous devons être en mesure de souscrire aux messages des autres nœuds, et Registry pas un assistant ici. Mais il y a PG2 qui implémente le même 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 

La seule différence avec le code autonome ci-dessus est manager: :phoenix_pub_sub paramètre que nous transmettons pour use Envio.Subscriber (et use Envio.Publisher ) pour construire un module basé sur :pg2 au lieu du Registry local. Les messages envoyés à l'aide de cet Publisher seront désormais disponibles sur tous les nœuds du cluster.


Candidature


Envío prend en charge les soi-disant backends . Envio.Slack est livré avec la Envio.Slack , ce qui vous permet de simplifier l'envoi de messages à Slack . Tout ce qui est requis de l'application - envoyez un message au canal configuré dans le config/prod.exs - Envío fera le Envío . Voici un exemple de configuration:


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

Désormais, tous les messages envoyés en appelant MyApp.Pub.publish(:slack, %{foo: :bar}) seront livrés au canal correspondant dans Slack , magnifiquement formatés. Pour arrêter d'envoyer des messages à Slack , arrêtez simplement le processus Envio.Slack . Plus d'exemples (par exemple, une connexion dans IO ) peuvent être trouvés dans les tests.


Pourquoi je crucifie, essayez-le vous-même.


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

Bonne communication!

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


All Articles