OTP significa Open Telecom Platform ; isso aconteceu historicamente, porque a plataforma foi criada para as necessidades e para o dinheiro da Ericsson . Mas, em princípio, esse nome tem tantas conotações com sua funcionalidade quanto maçãs com telefones de qualidade média.
A principal característica distintiva do OTP, de acordo com os autores, é a tolerância a falhas. Sem multithreading, sem modelo de ator, sem recursos avançados de correspondência de padrões, nem mesmo com cluster transparente e atualizações de códigos quentes. Tolerância a falhas.
A máquina virtual de Erlang é superficialmente projetada com muita simplicidade: há um monte de "processos" (não processos do sistema, processos erlang) com memória isolada que pode trocar mensagens. Só isso. Aqui está o que Joe Armstrong disse sobre isso:
No meu blog, argumentei que os processos deveriam se comportar da mesma maneira que as pessoas. As pessoas têm memórias particulares e trocam dados transmitindo mensagens.
- Por que não gosto de memória compartilhada
As mensagens no OTP são muito simples: um processo envia uma mensagem para outro (ou um grupo de outros processos), de forma síncrona ou assíncrona. Mas, para isso, você precisa saber a quem enviar essas mensagens. Ou seja, o remetente é o gerente de troca. Mas e se quisermos apenas enviar transmissão e permitir que todos os processos interessados se inscrevam nessa mensagem?
Sim, este é um PubSub comum, mas pronto para uso no OTP não está implementado. Bem, não importa, temos todos os tijolos em uma hora para trazê-lo de joelhos. Vamos começar.
Opções de implementação
Basicamente, o Elixir inclui um módulo de Registry
que pode ser usado como um andaime para o pubsub . Um pouco de código caseiro, uma aparência cuidada de todos os participantes (um supervisor para todos) e pronto. O único problema é que o Registry
local e não sabe como agrupar. Ou seja, em um ambiente distribuído (nós distribuídos) essa beleza não funcionará.
Phoenix.PubSub
nós, existe uma implementação distribuída do Phoenix.PubSub
que vem com duas implementações Phoenix.PubSub.PG2
: Phoenix.PubSub.PG2
e Phoenix.PubSub.Redis
. Bem, Redis
é claramente um elo extra em nossa cadeia, mas o PG2
, trabalhando no topo dos grupos Erlang dos processos da pg2
, é isso. Além disso, no entanto, sem um clichê não serve.
Portanto, temos tudo para estabelecer assinaturas convenientes do PubSub em nosso aplicativo. Está na hora de abrir um editor de texto? "Na verdade não." Não gosto de duplicar código de projeto para projeto, e tudo o que posso isolar em uma biblioteca é isolado para reutilização.
Envío
Assim nasceu o pacote Envío. Como as conversas, como você sabe, não valem um centavo, começaremos com exemplos de uso.
Boletim local → Registry
defmodule MyApp.Sub do use Envio.Subscriber, channels: [{MyApp.Pub, :main}] def handle_envio(message, state) do
Isso, em geral, é tudo. Resta MyApp.Sub
para a nossa árvore de supervisor, e esse processo começará a receber todas as mensagens enviadas usando as funções do MyApp.Pub
, que também não está sobrecarregado com código.
defmodule MyApp.Pub do use Envio.Publisher, channel: :main def publish(channel, what), do: broadcast(channel, what) def publish(what), do: broadcast(what)
Boletim Distribuído → PG2
Para sistemas distribuídos constituídos por muitos nós, esse método não funcionará. Precisamos ser capazes de assinar mensagens de outros nós, e o Registry
não Registry
um assistente aqui. Mas há o PG2
que implementa o mesmo 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
A única diferença do código independente acima é o parâmetro manager: :phoenix_pub_sub
, que passamos para use Envio.Subscriber
(e use Envio.Publisher
) para criar um módulo baseado em :pg2
vez do Registry
local. Agora, as mensagens enviadas usando este Publisher
estarão disponíveis em todos os nós no cluster.
Aplicação
Envío
suporta os chamados back - end . Envio.Slack
vem com a Envio.Slack
, o que permite simplificar o envio de mensagens para o Slack
. Tudo o que é necessário do aplicativo - envie uma mensagem para o canal configurado no config/prod.exs
- o config/prod.exs
fará o Envío
. Aqui está um exemplo de configuração:
config :envio, :backends, %{ Envio.Slack => %{ {MyApp.Pub, :slack} => [ hook_url: {:system, "SLACK_ENVIO_HOOK_URL"} ] } }
Agora todas as mensagens enviadas chamando MyApp.Pub.publish(:slack, %{foo: :bar})
serão entregues no canal correspondente no Slack , lindamente formatado. Para parar de enviar mensagens para o Slack , basta parar o processo Envio.Slack
. Mais exemplos (por exemplo, um log IO
) podem ser encontrados em testes.
Por que estou crucificando, tente você mesmo.
def deps do [ {:envio, "~> 0.8"} ] end
Boa comunicação!