Requisitos Iniciais
Certifique-se de que você tenha o Erlang e Elixir instalados em sua máquina. Para este tutorial, estou usando as seguintes versões:
Você também precisará do Docker em execução. Estou usando Docker Compose, então certifique-se de que ele também esteja instalado.
Configurando o Ambiente
Para começar, vamos criar duas instâncias Phoenix separadas:
Antes de rodar as instâncias, ainda há algo a ser feito. Navegue para os diretórios de ambas aplicações e configure os arquivos importantes:
Criar docker-compose.yml:
No diretório raiz, crie docker-compose.yml
:
Certifique-se de que o nome da rede seja o mesmo em todas as instâncias.
Criar Dockerfile:
No diretório raiz, crie Dockerfile
:
Criar entrypoint-dev.sh:
No diretório raiz, crie entrypoint-dev.sh
:
Criar .env:
No diretório raiz, crie .env
:
Editar dev.exs:
Para tornar ambas as instâncias acessíveis via localhost, navegue até config/dev.exs
e edite a linha 12.
Executando as Instâncias
Abra seu terminal na pasta raiz do projeto e crie a rede que conectará os containers:
Finalmente, inicie os containers com o seguinte comando:
Agora, as aplicações devem estar rodando nas portas especificadas no seu arquivo .env
. No meu caso, elas estão acessíveis em:
Configurando o Libcluster
Agora, vamos configurar o cluster para as instâncias.
Instalar libcluster:
Para começar, precisamos instalar o libcluster como dependência. Para isso, adicione-o ao seu arquivo mix.exs
:
Configurando a Topologia
Em seguida, vamos configurar a topologia. Neste exemplo, vamos usar a estratégia Gossip, que descobre automaticamente as nodes dentro de uma rede.
No arquivo config/config.exs
, adicione o seguinte ao final, antes de import_config:
Se você quiser mais controle sobre as nodes, também pode usar a Estratégia EPMD. Certifique-se de conferir a documentação do libcluster para outras opções disponíveis.
Inicializando o Libcluster
Agora, precisamos ativar o libcluster durante a inicialização da aplicação.
Adicione as seguintes linhas em lib/*_instance/application.ex
:
Verificando a Conexão
Agora, vamos reconstruir as instâncias e observar os logs. Execute os seguintes comandos em ambos os diretórios:
Quando ambas estiverem rodando, você deve ver algo assim em uma delas (geralmente a que iniciou primeiro):
Isso significa que nossas instâncias se conectaram com sucesso e estão prontas para interagir entre si via PubSub!
Configurando o PubSub
Agora é hora de configurar o PubSub para permitir a interação entre as instâncias.
Neste tutorial, vou separar as tarefas em duas instâncias:
- Instância 1 enviará mensagens.
- Instância 2 as receberá.
Mas primeiro, precisamos garantir que ambas as instâncias estejam usando o mesmo PubSub.
Para isso, abra config/config.exs
em ambas as instâncias e edite a linha 22 (ou onde estiver a configuração do endpoint):
Em seguida, em lib/*_instance/application.ex
, atualize a função de início:
Configurando o sender
Esta etapa é bem simples; tudo o que precisamos fazer é chamar a função PubSub.broadcast_from/3 de algum lugar. Vamos usar o Phoenix LiveView para isso.
Crie os seguintes arquivos:
lib/first_instance_web/live/sender_live/index.ex
:
lib/first_instance_web/live/sender_live/index.html.heex
:
Adicione a nova rota ao escopo do navegador em lib/first_instance_web/router.ex
:
Agora, visite http://localhost:4000/sender e teste clicando no botão. Se tudo estiver configurado corretamente, você verá uma mensagem de sucesso.
Configurando o Receptor
Para este tutorial, inicializarei a assinatura do PubSub junto com a aplicação, para evitar a criação de outra página. Com o PubSub, você pode enviar mensagens para qualquer página, mas apenas os usuários conectados a essa página receberão as mensagens. Ao inicializar o PubSub com a aplicação, permite que eu o use como um aplicativo de mensagens (por exemplo, RabbitMQ), habilitando interações com eventos no receptor, independentemente de haver ou não usuários conectados.
Crie o arquivo lib/second_instance_web/listener.ex
com o seguinte conteúdo:
Finalmente, em lib/second_instance/application.ex
, adicione o listener à lista de filhos:
Teste Final
Ótimo! Agora que você completou a configuração, o sistema deve funcionar como esperado:
- Abra os logs do Docker para o receptor (como example_two no meu caso) usando o seguinte comando:
-
Vá para a página da primeira instância (por exemplo, example_one) em seu navegador: http://localhost:4000/sender.
-
Clique no botão para enviar o sinal. Sempre que você clicar no botão, a seguinte mensagem deve aparecer nos logs do receptor:
Isso significa que o PubSub está funcionando corretamente e as instâncias estão se comunicando via LibCluster e Phoenix PubSub. Agora, suas duas instâncias estão prontas para interagir umas com as outras, enviando e recebendo mensagens através do cluster.
Você pode usar esse método para uma variedade de casos de uso, como:
- Notificações em tempo real: Enviar notificações entre diferentes nós em seu cluster.
- Processamento de tarefas distribuídas: Dividir tarefas entre vários nós para processamento paralelo.
- Aplicações de chat multi-instância: Construir um sistema de chat onde usuários conectados a diferentes nós ainda podem trocar mensagens em tempo real.
- Atualizações ao vivo em painéis: Enviar atualizações para painéis de usuário em tempo real, mesmo que o usuário esteja conectado a um nó diferente de onde os dados se originaram.
Estou usando essa configuração com mais de 30 instâncias, nenhuma das quais está ciente da existência das outras, mas todas recebem eventos de uma instância “central”. Essa abordagem permite uma comunicação eficiente entre diferentes instâncias sem necessidade de coordenação direta entre elas.
Você pode adaptar essa configuração para atender às necessidades do seu projeto!