Uma tradução do artigo foi preparada antes do início do curso "Developer on the Spring Framework" .
Olá a todos!Eu gostaria de compartilhar com você uma biblioteca de código aberto que facilita a integração do RabbitMQ com aplicativos no Spring Boot. Além disso, esta biblioteca oferece um novo conceito aprimorado de novas tentativas (em comparação com a abordagem padrão do Spring AMQP).Simplifica? Mas como?
Configuração automática
Suponha que desejemos implementar a interação (por exemplo, usando SSL) com o RabbitMQ usando o Spring AMQP. Precisamos criar um pouco de feijão, como ConnectionFactory
, RabbitAdmin
, RabbitTemplate
e AbstractRabbitListenerContainerFactory
.Mas imagine que existem vários hosts virtuais no RabbitMQ. Por padrão, no Spring AMQP, você precisa criar um ecossistema para cada host virtual com configuração manual de RabbitTemplate
e RabbitListener
.
Como você pode ver, toda essa configuração leva tempo e pode ser uma dor de cabeça.Ciente desse problema, a biblioteca proposta configura automaticamente todos esses beans para você. A única coisa que você precisa fazer é determinar a configuração application.properties
e a mágica acontecerá!Uau, mas como é a configuração application.properties
?
Tudo é muito simples. Em primeiro lugar, há um prefixo para as propriedades - isso spring.rabbitmq.custom
.Depois disso, você deve especificar o nome do evento. Essa é uma parte muito importante, pois todas as configurações que a biblioteca faz são baseadas nesse nome.Após o nome do evento, você pode especificar a propriedade e o valor. Todas as propriedades são descritas na documentação .Portanto, o modelo é o seguinte: Abaixo está um exemplo de configuração para duas conexões diferentes.spring.rabbitmq.custom.<
YOUR_EVENT>.<
PROPERTY>=<
VALUE>
spring.rabbitmq.custom.some-event.host=localhost
spring.rabbitmq.custom.some-event.port=5672
spring.rabbitmq.custom.some-event.ttlRetryMessage=5000
spring.rabbitmq.custom.some-event.maxRetriesAttempts=5
spring.rabbitmq.custom.some-event.ttlMultiply=2
spring.rabbitmq.custom.some-event.queueRoutingKey=ROUTING.KEY.TEST
spring.rabbitmq.custom.some-event.exchange=ex.custom.direct
spring.rabbitmq.custom.some-event.exchangeType=direct
spring.rabbitmq.custom.some-event.queue=queue.custom.test
spring.rabbitmq.custom.some-event.autoCreate=true
spring.rabbitmq.custom.some-event.concurrentConsumers=1
spring.rabbitmq.custom.some-event.maxConcurrentConsumers=1
spring.rabbitmq.custom.some-event.virtualHost=tradeshift
spring.rabbitmq.custom.some-event.primary=true
spring.rabbitmq.custom.some-event.sslConnection=true
spring.rabbitmq.custom.some-event.tlsKeystoreLocation=file:
spring.rabbitmq.custom.some-event.tlsKeystorePassword=${RABBITMQ_PASS_CERT}
spring.rabbitmq.custom.another-event.host=localhost
spring.rabbitmq.custom.another-event.port=5672
spring.rabbitmq.custom.another-event.ttlRetryMessage=5000
spring.rabbitmq.custom.another-event.maxRetriesAttempts=5
spring.rabbitmq.custom.another-event.queueRoutingKey=TEST.QUEUE
spring.rabbitmq.custom.another-event.exchange=ex_test_1
spring.rabbitmq.custom.another-event.exchangeType=direct
spring.rabbitmq.custom.another-event.queue=queue_test_1
spring.rabbitmq.custom.another-event.autoCreate=true
spring.rabbitmq.custom.another-event.concurrentConsumers=1
spring.rabbitmq.custom.another-event.maxConcurrentConsumers=1
spring.rabbitmq.custom.another-event.username=guest
spring.rabbitmq.custom.another-event.password=${RABBITMQ_PASS}
Como você pode ver, não escrevemos uma única linha de código !!!Bom, mas você estava dizendo algo sobre a nova estratégia de repetição, certo?
Sim, meu amigo disse!Mas antes de explicar essa nova estratégia, vamos dar uma olhada no comportamento padrão do RabbitMQ e do Spring AMQP.Por padrão, o RabbitMQ não fornece processamento de nova tentativa que permitiria controlar todo o ciclo de vida da mensagem.Por exemplo, antes do RabbitMQ 3.8 , o cabeçalho da mensagem não tinha uma propriedade para controlar o número de tentativas feitas.Comportamento padrão RabbitMQ:- Se você não definiu o tempo de vida (TTL, tempo de vida), o RabbitMQ tentará constantemente enfileirar sua mensagem.
- Se você definiu TTL, mas não definiu dlx , depois do TTL, a mensagem será removida da fila e você a perderá.
- Se você definiu TTL e dlx , depois do TTL, a mensagem será enviada ao trocador definido em dlx.
Comportamento padrão RabbitMQMas e se quisermos um TTL crescente (por exemplo, em caso de operação instável) e controlar o número de novas tentativas?
Ótima pergunta!Está na hora de explicar como as bibliotecas Spring AQMP e Spring Rabbit Tuning funcionam!Estratégias de repetição
Spring AMQP por padrão
Ao usar o Spring AMQP por padrão, você pode definir opções de nova tentativa usando as propriedades abaixo.Mas essa abordagem tem problemas. Por padrão, o Spring AMQP bloqueará sua fila quando você tentar entregar uma mensagem novamente.Esse problema pode ser resolvido de forma indireta: use paralelismo. Mas, dessa maneira, carregamos a JVM, e essa não é a melhor abordagem. Se você tiver cinco mensagens problemáticas (como no exemplo), um gargalo surgirá novamente, e ainda precisamos determinar manualmente os beans na @Configuration
caixa - para cada conexão e contêiner.spring.rabbitmq.listener.simple.retry.enabled=true
spring.rabbitmq.listener.simple.retry.initial-interval=2000
spring.rabbitmq.listener.simple.retry.max-attempts=5
spring.rabbitmq.listener.simple.retry.multiplier=2
spring.rabbitmq.listener.simple.max-concurrency=5
spring.rabbitmq.listener.simple.concurrency=5
Coelho da Primavera
Esta biblioteca adota uma abordagem diferente com uma fila separada para novas tentativas. Dessa forma, podemos controlar o TTL usando o parâmetro de mensagem de expiração e o parâmetro x-death para controlar o número de novas tentativas.Mas como?
Usamos o conceito dlx na fila de repetição para reenviar a mensagem para a fila principal. Assim, temos acesso ao parâmetro x-death e podemos determinar programaticamente o tempo de vida da mensagem.Nota. Como essa biblioteca é uma extensão do Spring AMQP, você pode usar a estratégia de repetição padrão e usar essa biblioteca apenas para configuração automática de beans.
Repetição de ajuste de coelhoPosso usar sua estratégia de repetição sem configuração automática? Eu já tenho muitos feijões e não tenho tempo para reescrevê-los.
Sabemos que o mundo não é perfeito e, para essa situação, temos um sinalizador que permite desativar a configuração automática e usar apenas nossa abordagem para o processamento de repetições e outras vantagens, como gerenciamento de lixeira.Você pode desativar a configuração automática usando a seguinte propriedade:spring.rabbitmq.enable.custom.autoconfiguration=false
Mas tenho duas conexões diferentes, o que devo fazer neste caso?
Se você possui mais de uma conexão e deseja desativar a configuração automática, precisará especificar o nome do bean RabbitTemplate
para cada conexão. Isto é descrito aqui . Você ainda pode usar nosso bean para facilitar o trabalho com o Spring AMQP.spring.rabbitmq.custom.<
YOUR_EVENT>.rabbitTemplateBeanName= <
RABBITTEMPLATE_BEAN_NAME>
RabbitTemplateHandler
Muito bem! Então, eu quero usar isso. Como posso fazer isso? Você tem um exemplo ou documentação?
Sim!Temos um projeto de exemplo neste repositório , onde você pode ver como usar esta biblioteca para editores e assinantes.Mas é tão simples que vou dar um exemplo aqui!Editor
Há uma classe na biblioteca RabbitTemplateHandler
e é muito fácil de usar. Você precisa chamar o método getRabbitTemplate
e transmitir o host virtual como um parâmetro para obter o bean RabbitTemplate
. Depois disso, você pode chamar o método convertAndSend e passá-lo nos parâmetros da chave de troca e roteamento.Nota : a chave de troca e roteamento pode ser obtida usando a anotaçãoValor.Um exemplo :@Value("${spring.rabbitmq.custom.some-event.exchange}")
private String exchangeSomeEvent;
@Value("${spring.rabbitmq.custom.some-event.queueRoutingKey}")
private String routingKeySomeEvent;
@Autowired
private final RabbitTemplateHandler rabbitTemplateHandler;
public void sendMessage(final String message) {
rabbitTemplateHandler.getRabbitTemplate("some-event").convertAndSend(exchangeSomeEvent, routingKeySomeEvent, message);
}
Assinante
Os assinantes também são muito simples. A única coisa que você precisa fazer é adicionar uma anotação ao método RabbitListener
(anotação Spring AMQP por padrão) e passar o nome containerFactory
.Como descobrir o nome containerFactory correto para um host virtual?
Você não precisa saber, basta passar o nome do evento e a biblioteca fará toda a mágica por você! Essa biblioteca também tem a capacidade de incluir novas tentativas e dlq, que são recomendadas.Ligá-los é muito simples. Você precisa adicionar anotação ao método EnableRabbitRetryAndDlq
e passar o nome da propriedade como argumento.Nota : você também pode especificar quais exceções tratar com tentativas e dlq. É processado por padrão Exception.class
, o que significa lidar com todas as exceções.Exemplo:@RabbitListener(containerFactory = "some-event", queues = "${spring.rabbitmq.custom.some-event.queue}")
@EnableRabbitRetryAndDlq(event = "some-event", exceptions = { IllegalArgumentException.class, RuntimeException.class })
public void onMessage(Message message) {
...
}
É tudo! Espero que você goste desta biblioteca tanto quanto nós!E, o mais importante: fique à vontade para contribuir ou enviar feedback!Agradecimentos especiais para
André Luis GomesRogerio BuenoLeonardo Ferreira
Inscreva-se para uma aula gratuita.