Guia prático de atividade coelho: o que é, como funciona e o que ninguém te conta
A expressão atividade coelho aparece com frequência em fóruns e equipes de desenvolvimento brasileiras quando o assunto é RabbitMQ. Sim, o tal do "coelho" é o broker de mensagens AMQP mais usado no mercado. Trabalho com ele desde 2016, em filas de alta carga e em sistemas menores de integração. Achei útil documentar algumas coisas que aprenderi na prática, porque a documentação oficial não cobre os problemas que realmente aparecem. Primeiro, o básico. RabbitMQ é um mensageiro. Você tem produtores que publicam mensagens, o broker que entrega, e consumidores que processam. Ele usa o protocolo AMQP 0-9-1 por padrão, mas suporta MQTT, STOMP e outras camadas via plugins. O que diferencia ele de soluções como Kafka ou SQS é que ele dá controle fino sobre rota, fila, trocador e confirmação de entrega.
Como funciona a atividade coelho no dia a dia
O fluxo típico começa declarando uma exchange, uma fila, e um binding. Os produtores enviam mensagens para a exchange com uma routing key. O broker decide para qual fila encaminhar baseado nas regras de bind. O consumidor assina a fila com prefetched messages, recebe, processa, e ack ou nack. Aqui está algo que confunde muita gente: o ACK não é automático por padrão. Se você não habilitar manual acknowledge, a mensagem é descartada assim que chega no buffer do cliente, antes mesmo de você processar. Isso mata a garantia de entrega. Eu vi isso acontecer em dois projetos novos que herdei — configuração padrão que engana.
Outro ponto que merece atenção: QoS prefetch. Se você não configurar o channel QoS com prefetch_count, o broker distribui mensagens de forma round-robin cega. Um consumidor rápido fica ocioso enquanto outro acumula milhares de mensagens. Na minha experiência, configurar prefetch entre 10 e 50 já resolve a maior parte dos desbalanceamentos em clusters de tamanho médio.
O problema que ninguém avisa: mensagens presas no estado unacked
Em 2021, eu enfrentei um problema específico com atividade coelho que durou três dias inteiros. Tínhamos um consumer Python com Celery rodando em Kubernetes, e de repente a fila de processamento de eventos de pagamento travava. Mensagens chegavam, o consumer recebia, mas nunca liberava o ACK. A fila enchia, o broker entrava em modo de flow control, e todo o sistema parada. O diagnóstico foi direto: crashes silenciosos de containers em health checks lentos. O pod era marcado como terminando, o broker pensava que o consumer ainda estava vivo, e as mensagens acumulavam no estado unacked sem nunca serem entregues a outro consumidor.
A solução que funcionou foi uma combinação de três ajustes:
👉 Clique no botão abaixo para saber mais sobre o assunto!
- Channel-level preack configurado como 5 segundos para timeouts curtos de consumer
- Shovel plugin para enviar mensagens pendentes de volta para uma fila de DLQ com TTL de 10 minutos
- Sigterm handler no consumer para flushar o buffer de ACKs antes do container morrer
O código Python ficou basicamente assim: Um handler que intercepta SIGTERM, chama channel.basic_ack para todas as mensagens em processamento, e depois fecha o canal gracefulmante. Isso evitou que mensagens ficassem presas por horas. O shovel configurado como fallback para casos mais críticos. Juntos, eles reduziram o tempo médio de recuperação de falhas de consumer de 45 minutos para cerca de 90 segundos.
Pegadinhas avançadas que aprendi na prática
Dead Letter Exchange (DLX) não é automático. Você precisa declarar a DLX, configurar o argumento x-dead-letter-exchange na fila, e criar um consumer separado para ela. Eu já vi gente criar a fila com DLX e esquecer de criar o exchange correspondente. Resultado: mensagens mortas que nunca são processadas. Perfils de cluster precisam de atenção. Em clusters RabbitMQ com múltiplos nós, o mirror queue policy pode criar cópias em todos os nós ou em uma fração deles. Isso aumenta a latência de escrita significativamente. Para workloads de alta Throughput onde latência importa mais que disponibilidade total, usar queues espelhadas em apenas 3 dos 7 nós foi melhor do que espelhar em todos.
Memory alarm threshold. O broker pausa produtores quando a memória atinge o threshold configurado (padrão 0.4). Muitos engenheiros não percebem que isso inclui memória do sistema operacional, não apenas memória alocada pelo Erlang VM. Em máquinas com muito cache de disco, o alarme pode disparar falsamente. Ajustei para 0.6 em ambientes de produção e monitorei com Grafana + Prometheus. Lazy Queues vs Classic Queues. Desde a versão 3.6+, o RabbitMQ suporta lazy queues onde mensagens são persistidas diretamente em arquivos no disco em vez de memória. Isso reduz o uso de memória drasticamente mas aumenta a latência de leitura. Eu migrei uma fila de notificações assíncronas de 5 milhões de mensagens para lazy queue. O throughput caiu de 12k msg/s para 4k msg/s, mas o uso de memória caiu de 16GB para 200MB. Para essa workload específica, a troca valeu a pena.
Alternativas quando a atividade coelho não funciona
Nem sempre RabbitMQ é a resposta certa. Se você precisa de replay de mensagens, order guarantee, ou retenção de dados por longos períodos, Kafka é mais adequado. Se o requirement é simplicidade extrema e integrações AWS-only, SQS com FIFO é suficiente. Se o volume é baixo e a complexidade de operação não compensa, até uma fila PostgreSQL com polling pode resolver. Eu recomendo RabbitMQ quando você precisa de routing flexível (topic exchanges, header exchanges), baixa latência, e controle granular sobre o ciclo de vida das mensagens. Não recomendo quando o time não tem capacidade de operar um cluster Erlang, ou quando o throughput esperado ultrapassa 100k msg/s consistentemente.
A curva de aprendizado inicial é mais íngreme do que soluções gerenciadas como SQS ou EventBridge, mas o controle que você ganha compensa após os primeiros meses de operação. O mais importante: monitore tudo desde o dia um. Prometheus com o exporter oficial, alertas em memória e disk, e dashboards de throughput por exchange. Sem monitoramento, atividade coelho vira jogo de adivinhação.