Tempo Real com LiveView
Seu Primeiro PubSub
Tempo de leitura: 4 minutos
Projetos Phoenix já vêm com tudo que você precisa para criar software em tempo real. Hoje vamos falar sobre uma das principais funcionalidades do Phoenix: o PubSub.
#Definindo o problema
Estamos construindo um sistema de fila de tickets onde os usuários podem pegar seus tickets e nossa página principal deve acompanhar quem é o próximo na fila. Não queremos que os usuários fiquem atualizando a página toda vez que alguém chega. Não precisamos disso. Para começar a trabalhar com PubSub (assinaturas públicas) precisamos pensar apenas em duas coisas:
- Quais são os triggers para uma atualização em tempo real?
- Quem precisa saber sobre o que foi atualizado?
Se você conseguir responder essas duas perguntas, você pode definir um caso de uso para PubSubs. Vamos ao código.
#Nosso escopo
Vamos escrever isso como um caso de uso:
Eu, como cliente usando este sistema de tickets, quero pegar um ticket e a equipe será notificada sobre minha presença na fila.
Agora que temos o caso de uso, vamos traduzi-lo em etapas que podemos programar.
-
Quais são os triggers para uma atualização em tempo real?
- O usuário cria um ticket.
-
Quem precisa saber sobre o que foi atualizado?
- A lista de tickets.
#Broadcasts
Quando você quer que outras LiveViews sejam notificados sobre algo, precisamos usar broadcasts do PubSub. Pense nisso como uma mensagem sendo enviada para todos que querem ouvi-la. Existem várias formas de fazer um broadcast, mas como estamos trabalhando com LiveView, vamos preferir usar MyappWeb.Endpoint.broadcast/3. Vamos brincar um pouco com isso.
No seu terminal, execute o seguinte para iniciar um shell Elixir interativo:
$ iex -S mix
Interactive Elixir (1.19.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> alias LineupWeb.Endpoint
LineupWeb.Endpoint
iex(2)> Endpoint.broadcast("queue:tickets", "ticket_added", %{id: 1})
:ok
Criamos um alias para o nosso LineupWeb.Endpoint para podermos chamar Endpoint.algo depois.
A função broadcast recebe 3 argumentos:
- Um tópico: pode ser qualquer string.
- Um evento: também qualquer string.
- Um payload: um mapa de dados para enviar com o evento.
Como estamos trabalhando com tickets, escolhemos o tópico "queue:tickets" pois ele se relaciona com nossos contexto e modelo, mas poderia ser qualquer coisa como "minhas-notificacoes-do-sistema-123". Para o nome do evento, queremos ser bem claros para garantir que nosso código seja mais fácil de entender no futuro. Para o último argumento, você pode passar qualquer coisa como um mapa. Por enquanto, escolhemos passar um mapa com o id do ticket para que a LiveView possa usá-lo para atualizar a UI.
E daí? Nada aconteceu. Enviar mensagens não é útil a menos que tenhamos alguém esperando por elas.
#Subscriptions
O motivo de um tópico existir no PubSub é que saberemos quem está interessado em receber mensagens sobre aquele tópico. Vamos voltar ao nosso iex e tentar mais uma vez.
iex(3)> Endpoint.subscribe("queue:tickets")
:ok
iex(4)> Endpoint.broadcast("queue:tickets", "ticket_added", %{id: 1})
:ok
iex(5)> flush()
%Phoenix.Socket.Broadcast{
topic: "queue:tickets",
event: "ticket_added",
payload: %{id: 1}
}
:ok
Desta vez usamos Endpoint.subscribe/2 para assinar o tópico "queue:tickets" e Endpoint.broadcast/3 para enviar uma mensagem a ele. Depois usamos flush() para mostrar todas as mensagens recebidas por este processo.
Talvez eu tenha acabado de soltar uma bomba: shells iex são processos de longa duração e os LiveViews também são. No Elixir, processos têm uma caixa de entrada que acumula mensagens até que sejam lidas. É por isso que flush() é tão útil: ele permite que você veja todas as mensagens recebidas por um processo. Experimente:
iex(6)> Endpoint.broadcast("queue:tickets", "ticket_added", %{id: 2})
:ok
iex(7)> Endpoint.broadcast("queue:tickets", "ticket_added", %{id: 3})
:ok
iex(8)> flush()
%Phoenix.Socket.Broadcast{
topic: "queue:tickets",
event: "ticket_added",
payload: %{id: 2}
}
%Phoenix.Socket.Broadcast{
topic: "queue:tickets",
event: "ticket_added",
payload: %{id: 3}
}
:ok
Bem, em LiveViews reais não vamos usar flush(), vamos tratar as mensagens conforme elas chegam para atualizar nossa UI adequadamente.
#Resumo!
- Sempre pense no seu caso de uso antes de escrever código.
- Broadcasts enviam mensagens para todos os processos que estão ouvindo um determinado tópico.
- Subscriptions podem ser feitas por qualquer processo para receber mensagens de um tópico.
-
LiveViews são processos e o
iextambém é. -
Você pode usar
flush()noiexpara ver todas as mensagens recebidas por um processo.
Feedback
Você tem algum feedback sobre esta página? Conte-nos!