消息传递-> OTP内的PubSub

OTP代表开放电信平台 ; 因此发生在历史上,因为该平台是为满足需求和爱立信的资金而创建 。 但是,从原则上讲,此名称的功能含义与普通手机中的苹果一样多。


这组作者说, OTP的主要区别特征是容错能力。 没有多线程,没有参与者模型,没有丰富的模式匹配功能,甚至没有透明的集群,也没有热代码升级。 容错能力。


表面安装的Erlang虚拟机的结构非常简单:有一堆带有独立内存的“进程”(不是系统进程,Erlang进程),可以交换消息。 仅此而已。 这是乔·阿姆斯特朗(Joe Armstrong)所说的:


在我的博客中,我认为流程应该表现得很像人。 人们拥有私人记忆,并通过消息传递来交换数据。
- 为什么我不喜欢共享内存

OTP中的消息传递非常简单:一个进程可以同步或异步地向另一个(或一组其他进程)发送一条消息。 但是为此,您需要知道向谁发送这些消息。 即,发送者是交换管理器。 但是,如果我们只想发送广播并使所有感兴趣的进程订阅此消息怎么办?


是的,这是常规的PubSub,但是在OTP中是开箱即用的,它没有实现。 好吧,没关系,我们在一小时之内就把所有的砖块都屈服了。 让我们开始吧。


实施方案


基本上, Elixir包括一个Registry模块,可以用作pubsub支架 。 编写一点点本地代码,将所有参与者(每个人的主管)都整洁的看待就可以了。 唯一的问题是Registry本地的,并且不知道如何群集。 也就是说,在分布式环境(分布式节点)中,这种功能将无法使用。


Phoenix.PubSub我们来说Phoenix.PubSub ,有一个Phoenix.PubSub的分布式实现,它带有两个现成的实现: Phoenix.PubSub.PG2Phoenix.PubSub.Redis 。 好吧, Redis显然是我们链中的一个额外链接,但是PG2是在pg2进程的Erlang组之上工作的。 而且,但是,如果没有样板也不会。


因此,我们拥有在应用程序中建立便捷的PubSub订阅的所有功能。 是时候打开文本编辑器了吗? “不是真的。” 我不喜欢在项目之间复制代码,并且我可以隔离到库中的所有内容都被隔离以供重用。


环保


因此, Envío包装诞生了。 如您所知,既然chat不值得一分钱,我们将从使用示例开始。


本地通讯→ 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在这里不是助手。 但是有实现相同behaviour PG2


 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构建模块的:pg2 。 现在,使用此Publisher服务器发送的消息将在群集中的所有节点上可用。


申请书


Envío支持所谓的后端Envio.SlackEnvio.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进程。 在测试中可以找到更多示例(例如IO的日志)。


我为什么要钉十字架,自己尝试。


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

良好的沟通!

Source: https://habr.com/ru/post/zh-CN481460/


All Articles