Rabbitmq

Muito melhor que uma tabela no banco

Wilson Santos
6 min readNov 11, 2020

Eu venho de uma época em que usávamos banco de dados para tudo , a forma padrão de integrar aplicações era através de tabelas e controle de status.

Sei que você torceu o nariz , mas é assim que é em muitos lugares , conforme essas integrações foram crescendo e conforme a infraestrutura vai se tornando mais complicada ,qualquer desenvolvedor que mantem um sistema por mais de um ano, acaba percebendo que isso tende a se tornar uma pedra no sapato da aplicação, sempre que a aplicação fica lenta , ouvimos aquele frase celebre , “Será que tem algum job rodando?” , mas será que não da pra fazer melhor?

  1. Imagine matar todos aqueles jobs que batem no banco da sua aplicação e deixam o banco “sentado”?
  2. Imagine tirar do pipe da aplicação aqueles processo pesados e deixa-los isolados em outros sistemas focados em realizar apenas essa tarefa ?
  3. Imagine conseguir integrar sistemas em um fluxo , onde um processo maior pode ser executado como partes isoladas em aplicações diferentes, servidores diferentes, sem usar banco de dados para gerenciar isso?

Isso é exatamente o que uma grande parte do mercado faz hoje em dia ,então podemos começar também. Esse cara pode liberar nossos bancos de leituras massivas, mas antes disso vamos entender o básico do RBMQ.

De uma olha no modelo;

  1. Produtor : Quem gera as mensagens pode ser sua api
  2. Exchange: Um tipo de Proxy de mensagem, uma peça do protocolo que o Rabbit implementa o AMQP, ele pode ter alguns comportamentos específicos como Direct, Fanout, Topic por enquanto vamos entender que são apenas regrinhas de como as mensagens vão ser encaminhadas, esse processo é chamado de binding e faz parte da arquitetura do Rabbit e seus protocolos.
  3. Broker : É o servidor.
  4. Mensagens : São nossas classes d Dominio , ViewModel , Dto etc, poder ser até dados primitivos como strings, inteitos etc , no final tudo vira bytes
  5. Consumidor : Aplicações que lê as mensagens.

Basicamente precisamos ter alguém que produz a mensagem um Produtor , e alguem para consumir Comumidor, isso é feito por uma abstração chamada IConnection e factory ConnectionFactory que fica dentro do pacote RabbitMQ.Client eu usei uma API .net core para construir o produtor , um Serviço hospedado para ser o consumidor A e um Console para ser o Consumidor B.

Vamos instalar o pacotinho na API e no Console;

Install-Package RabbitMQ.Client

Criar a Controller Enqueue;

var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "Messages",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
var messageJson = System.Text.Json.JsonSerializer.Serialize(model);
var body = Encoding.UTF8.GetBytes(messageJson);
channel.BasicPublish(exchange: "",
routingKey: "Messages",
basicProperties: null,
body: body);
}

Esse cara manda uma mensagem para um servidor local, essa mensagem é uma classe uma model que estamos carecas de usar.

Serializamos utilizando o System.Text.Json, que muito mais rápido que o e NewtonSoft, transformamos em bytes, coisa fina, esses bytes são pulicados em uma exchange basicamente um roteador de mensagem.

Uma vez Publicado a mensagem vai para o servidor e podemos vela pela ferramenta de administração do Rabbit.

Para instalar o rabbit, Subi uma imagem via Docker coisa linda e simples, se vc ainda não conhece docker veja esse artigo (docker tem um linux no meu windows)

Para você por o Rabbit para rodar use o comando abaixo , ele é mais complexo por que define o nome do container , define as portas que o servidor vai responder, o parâmetro -d e para “desataxar” do container do terminal e manter ele rodando.

docker run -d --hostname rabbitserver --name rabbitmq-server -p 15672:15672 -p 5672:5672 rabbitmq:3-management
basta acessar http://localhost:15672/ e entrar com guest/guest

Vou usar o postmam para poder enviar a mensagem, para o endereço da minha api que no caso esta em https://localhost:44386 a nossa controller é a enqueue

e olha que coisa mais linda;

vou clicar enlouquecidamente para ver

Legal D+

Agora eu vou criar o consumidor , normalmente fazemos isso em um console para que o aplicativo fique esperando a mensagem chegar , dizemos nas trincheiras que ele fica escutando a fila.

Eu não queria fazer apenas um console como consumidor, estou pensando em usar Serviços Hospedados do .net core, é super simples , basta criar uma classe na sua própria Api que implemente a interface IHostedService, essa classe temo dois métodos simples para poder StartAsync e StopAsync , usei um timer para chamar a rotina de tempos em tempos e configurei a classe program para subir essa classe como um serviço hospedado junto com a API;

A classe DequeueHandler fica assim;

O método Consumer tem uma implementação default que peguei da própria documentação do Rabbit;

var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "Messages",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
var consumer = new EventingBasicConsumer(channel);
var item = default(Message);
consumer.Received += (model, ea) =>
{
try
{
var body = ea.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
item = System.Text.Json.JsonSerializer.Deserialize<Message>(message);
Console.WriteLine($"Message : {item.Name}, {item.Value}");
channel.BasicAck(ea.DeliveryTag, false);
}
catch (Exception ex)
{
channel.BasicNack(ea.DeliveryTag, false, true);
}
};
channel.BasicConsume(queue: "Messages",
autoAck: false,
consumer: consumer);
}

Para não dizer que esta exatamente igual , ao código da documentação eu mudei o autoAck, que é uma forma automática de dizer que recebemos a mensagem, não é uma ideia muito boa.

Basicamente fiz um try Cath e se não der erro eu digo que recebi assim ;

channel.BasicAck(ea.DeliveryTag, false);

Se der errado eu digo que não recebi , assim;

channel.BasicNack(ea.DeliveryTag, false, true);

RabbitMQ Round Robin Pattern

Esse mecanismo é show é já nativo do Rabbit e é ai que começamos a ter grandes vantagens pois ele consegue distribuir as mensagens para vários consumidores garantindo que um consumidor não receba a mesma msg de outro

Agora eu vou mostrar o funcionamento em um “videozinho”;

o projeto esta no git

--

--

Wilson Santos
Wilson Santos

Written by Wilson Santos

Nos últimos 15 anos, venho desenvolvendo , aperfeiçoando e integrando sistemas, sou apaixonado por desenvolver e ensinar, nem tanto por escrever!.

No responses yet