Exchange Topic no RabbitMQ

Introdução

O Topic Exchange do RabbitMQ é um tipo avançado de exchange que permite rotear mensagens para filas com base em padrões flexíveis definidos através de routing keys.

Diferentemente do Fanout Exchange (que copia mensagens para todas as filas) e do Direct Exchange (que utiliza chaves exatas para roteamento), o Topic Exchange oferece um mecanismo intermediário, permitindo rotear mensagens através de padrões de texto utilizando caracteres especiais.


Principais Características do Topic Exchange

  • A routing key precisa ser composta por palavras separadas por pontos (.).

  • Suporta wildcards para definir padrões:

    • * (asterisco): substitui exatamente uma palavra.
    • # (hash): substitui zero ou mais palavras.

Exemplo

Imagine uma empresa que possui a seguinte hierarquia:

          Diretoria (finance)
              |
     -------------------
     |                 |
 Coord. SP          Coord. RJ
     |                 |
------------      ------------
|          |      |          |
SP1       SP2     RJ1        RJ2

Objetivo

Permitir enviar mensagens para níveis específicos ou grupos de níveis usando padrões flexíveis.

Exemplo de Routing Keys

  • finance → Mensagens para Diretoria.
  • finance.sp → Apenas Coordenação SP.
  • finance.rj.rj1 → Apenas Supervisão RJ1.

Configuração dos Bindings (no RabbitMQ UI)

FilaBinding KeyExplicação
Diretoriafinance.#Recebe todas mensagens iniciadas por “finance”
Coord SPfinance.sp.*Recebe mensagens para SP1, SP2, etc.
Coord RJfinance.rj.*Recebe mensagens para RJ1, RJ2, etc.
SP1finance.sp.sp1Apenas mensagens específicas SP1
SP2finance.sp.sp2Apenas mensagens específicas SP2
RJ1finance.rj.rj1Apenas mensagens específicas RJ1
RJ2finance.rj.rj2Apenas mensagens específicas RJ2

Exemplo Prático em .NET

Publicador (.NET)

var factory = new ConnectionFactory { HostName = "localhost" };
using var connection = await factory.CreateConnectionAsync();
using var channel = await connection.CreateChannelAsync();
 
// Cria exchange tipo Topic
await channel.ExchangeDeclareAsync("topic_logs", ExchangeType.Topic);
 
// Exemplo prático de envio de mensagem:
var routingKey = "finance.rj.rj1";
var message = "Mensagem específica para RJ1";
var body = Encoding.UTF8.GetBytes(message);
 
await channel.BasicPublishAsync(
    exchange: "topic_logs",
    routingKey: routingKey,
    body: body);
 
Console.WriteLine($"[x] Enviada '{routingKey}':'{message}'");

Consumidor (.NET)

var factory = new ConnectionFactory { HostName = "localhost" };
 
using var connection = await factory.CreateConnectionAsync();
using var channel = await connection.CreateChannelAsync();
 
await channel.ExchangeDeclareAsync("topic_logs", ExchangeType.Topic);
 
// Cria fila anônima (gerada automaticamente)
var queueDeclareResult = await channel.QueueDeclareAsync();
string queueName = queueDeclareResult.QueueName;
 
// Binding keys (escuta múltiplos padrões, exemplo: todas mensagens do RJ)
string[] bindingKeys = new[] { "finance.rj.*" };
 
foreach (var bindingKey in bindingKeys)
{
    await channel.QueueBindAsync(queue: queueName, exchange: "topic_logs", routingKey: bindingKey);
}
 
Console.WriteLine("[*] Esperando mensagens (finance.rj.*)");
 
var consumer = new AsyncEventingBasicConsumer(channel);
 
consumer.ReceivedAsync += (model, ea) =>
{
    var body = ea.Body.ToArray();
    var message = Encoding.UTF8.GetString(body);
    var receivedRoutingKey = ea.RoutingKey;
 
    Console.WriteLine($"[x] Recebido '{receivedRoutingKey}':'{message}'");
    return Task.CompletedTask;
};
 
await channel.BasicConsumeAsync(queueName, autoAck: true, consumer: consumer);
Console.WriteLine(" Pressione [enter] para sair.");
Console.ReadLine();

Exemplos de Padrões (Binding Keys)

Imagine uma routing key no formato:

<departamento>.<local>.<nível>
Binding KeyExemplo de Routing Key válidaExplicação
finance.#finance.sp.sp1, finance.rj.rj1Recebe mensagens de qualquer nível financeiro
finance.*finance.sp, finance.rjRecebe mensagens diretamente abaixo de finance
*.rj.*finance.rj.rj1, rh.rj.coordRecebe mensagens de RJ, independente do departamento
#TodasRecebe todas as mensagens (equivale ao fanout)

Comparação com Outros Exchanges

ExchangeUsoFlexibilidade
FanoutEnvia para todas as filasBaixa
DirectEnvia usando routing key exataMédia
TopicEnvia usando padrões complexosAlta

O Topic Exchange é ideal para sistemas de logs, alertas e notificações complexas.


Pontos Importantes

  • Mensagens com routing keys que não atendem a nenhum padrão são descartadas.

  • Utilize * para segmentação exata de palavras.

  • Utilize # para escutar níveis variados (inclusive múltiplos níveis).


Resumo Rápido

  • Topic Exchange permite roteamento inteligente e flexível de mensagens.

  • Usa padrões nas routing keys (com * e #) para definir quais filas recebem quais mensagens.

  • É indicado para cenários onde mensagens precisam ser entregues de forma dinâmica e seletiva, com muita flexibilidade.