O blog da AWS

Implementação de transações usando JMS2.0 no Amazon MQ para ActiveMQ

Este artigo foi escrito por Paras Jain, gerente técnico sênior de contas e Vinodh Kannan Sadayamuthu, arquiteto de soluções especialista sênior.

Este artigo descreve os recursos transacionais do broker ActiveMQ no Amazon MQ usando um aplicativo produtor de mensagens usando a API Java Messaging System (JMS) 2.0. As APIs do JMS 2.0 são mais fáceis de usar e têm menos interfaces (parâmetros) do que a versão anterior. Para saber mais sobre o suporte ao JMS 2.0 do ActiveMQ, consulte a documentação do ActiveMQ sobre o JMS2.0. Confira também O que há de novo no JMS 2.0 para saber mais sobre os recursos do JMS2.0.

O Amazon MQ agora oferece suporte ao ActiveMQ 5.18. O Amazon MQ também introduz um novo sistema de versionamento semântico que exibe a versão secundária (por exemplo, 5.18) e mantém seu broker atualizado com novos patches (por exemplo, 5.18.4) dentro da mesma versão secundária. O ActiveMQ 5.18 adiciona suporte para JMS 2.0, Spring 5.3.x e várias atualizações de dependências e correções de erros. Para obter os detalhes completos, consulte as notas de lançamento da série Active MQ 5.18.x.

Visão geral

Padrões de mensagens em sistemas distribuídos

A implementação de mensagens em um sistema de mensagens distribuídas baseado em um broker de mensagens geralmente envolve um mecanismo de atirar e esquecer (fire-and-forget). Os produtores enviam as mensagens ao broker que tem a responsabilidade de garantir que as mensagens sejam entregues aos consumidores. Em casos de uso não transacionais, as mensagens são independentes umas das outras. No entanto, em algumas situações, um grupo de mensagens precisa ser entregue aos consumidores como parte de uma única transação. Isso significa que todas as mensagens do grupo devem ser entregues ao consumidor ou nenhuma dessas mensagens será entregue.

O ActiveMQ 5.18 fornece dois níveis de suporte a transações — transações JMS e transações XA.

As transações JMS são usadas quando várias mensagens precisam ser enviadas ao broker ActiveMQ como uma única unidade atômica. Esse comportamento transacional é ativado invocando os métodos commit() e rollback() em um objeto Session (para JMS 1.x) ou JMSContext (para JMS 2.0). Se todas as mensagens forem enviadas com sucesso, a transação poderá ser confirmada, garantindo que as mensagens sejam processadas como uma unidade. Se ocorrer algum problema durante o processo de envio, a transação poderá ser revertida, impedindo a entrega parcial das mensagens. Essa capacidade transacional é crucial para manter a integridade dos dados e garantir que operações complexas de mensagens sejam executadas de forma confiável. Consulte as perguntas frequentes do ActiveMQ — como as transações funcionam para obter mais detalhes sobre como as transações funcionam no ActiveMQ.

As transações XA são usadas quando duas ou mais mensagens precisam ser enviadas aos brokers ActiveMQ e outros recursos distribuídos de forma transacional. Isso é obtido usando uma Sessão XA, que funciona como um recurso XA. Consulte as perguntas frequentes do ActiveMQ — devo usar transações XA para obter mais detalhes sobre transações XA.

Caso de uso transacional em um Sistema de Gerenciamento de Pedidos

O exemplo neste artigo mostra os recursos transacionais em um aplicativo do Sistema de Gerenciamento de Pedidos (OMS – Order Management System), usando o ActiveMQ como broker de mensagens. Ao receber um pedido, o aplicativo OMS envia uma mensagem (mensagem 1) para a fila do armazém para iniciar o processo de embalagem. Em seguida, o aplicativo executa um processo comercial interno. Se esse processo for bem-sucedido, o aplicativo enviará outra mensagem (mensagem 2) para a fila de remessa para iniciar o processo de retirada do pacote. No caso de falha do processo comercial interno, é necessário evitar que a mensagem 2 seja enviada para a fila de remessa e reverter a mensagem 1 da fila do armazém.

O fluxograma abaixo ilustra a lógica por trás do caso de uso transacional apresentado neste exemplo.

Flowchart illustrating the logic behind the transactional use case in the code example. Demonstrates flow for successful as-well-as failed transaction.

Fluxograma descrevendo o caso de uso transacional.

O cliente JMS armazena as duas mensagens na memória até que a transação seja confirmada ou revertida. O cliente consegue isso mantendo uma sessão transacionada entre o cliente produtor de mensagens e o broker. Uma sessão transacionada é uma sessão que usa transações para garantir a entrega de mensagens. Em nosso exemplo, a sessão transacionada é criada usando a seguinte instrução.

JMSContext jmsContext = connectionFactory.createContext(adminUsername, adminPassword, Session.SESSION_TRANSACTED);
JSON

No exemplo deste artigo, mostramos uma sessão transacionada entre o produtor da mensagem e o broker. Não estamos mostrando as transações entre o broker e o consumidor da mensagem. Você pode implementá-lo usando um padrão similar.

Criando o broker do ActiveMQ

Os pré-requisitos a seguir são necessários para criar e configurar o broker ActiveMQ no Amazon MQ.

Pré-requisitos:

Para criar um broker (AWS CLI):

  1. Execute o comando a seguir para criar o broker. Isso cria um broker aberto ao acesso público apenas para testes. Ao criar agentes para uso em produção, siga as melhores práticas de segurança do Amazon MQ.
aws mq create-broker \
    --broker-name <broker-name> \
    --engine-type activemq \
    --engine-version 5.18 \
    --deployment-mode SINGLE_INSTANCE \
    --host-instance-type mq.t3.micro \
    --auto-minor-version-upgrade \
    --publicly-accessible \
    --users Username=<username>,Password=<password>,ConsoleAccess=true
JSON

Substitua <broker-name> pelo nome que você deseja dar ao broker. Substitua <username> e <password> de acordo com a documentação da CLI do create-broker. Após a execução bem-sucedida do comando, o BrokerArn e o BrokerID são exibidos na linha de comando. Anote esses valores. A criação do broker leva cerca de 15 minutos.

  1. Execute o comando a seguir para obter o status
aws mq describe-broker --broker-id <BrokerId> --query 'BrokerState'
JSON

Prossiga para a próxima etapa quando o estado do broker estiver em execução.

  1. Obtenha o URL do console e outros endpoints do broker executando o seguinte comando
aws mq describe-broker --broker-id <BrokerId> --query 'BrokerInstances[0]’
JSON

Observe o ConsoleURL e o endpoint ssl da saída.

Configurando o cliente produtor de mensagens

O código de exemplo neste artigo usa um cliente produtor de mensagens de exemplo escrito usando a API JMS 2.0 para enviar mensagens ao broker ActiveMQ.

  • No caso de uma transação bem-sucedida, o produtor envia uma mensagem para a primeira fila e espera por 15 segundos. Em seguida, ele envia a mensagem para a segunda fila e espera por mais 15 segundos. Finalmente, ele confirma a transação.
  • Em caso de falha na transação, o produtor envia a primeira mensagem e espera por 15 segundos. Em seguida, o código introduz uma falha artificial, causando a reversão da transação. O tempo de espera de 15 segundos oferece a oportunidade de verificar o número de mensagens do lado do broker à medida que o programa avança no fluxo da transação. Até que o produtor confirme a transação, nenhuma das mensagens é enviada ao agente, mesmo para uma transação bem-sucedida.

Para baixar e configurar o cliente de exemplo:

  1. Obtenha o Jar do cliente de exemplo de transações do Amazon MQ no repositório do GitHub.
  2. Para executar o cliente de exemplo, use o comando java com a opção -jar que executa o programa encapsulado em um arquivo jar. A sintaxe para executar o cliente de amostra é:
java -jar <path-to-jar-file>/<jar-filename> <username> <password> <ssl-endpoint> <first-queue> <second-queue> <message> <is-transaction-successful> 
JSON

Uso:
<path-to-jar-file> – caminho em sua máquina local onde você baixou o arquivo jar.
<jar-filename> – nome do arquivo jar.
<username> – nome de usuário que você selecionou ao criar o broker.
<password> – senha que você selecionou ao criar o broker.
<ssl-endpoint> – endpoint ssl que você anotou na etapa acima.
<first-queue> – nome da primeira fila na transação.
<second-queue> – nome da segunda fila na transaçã.
<message> – texto da mensagem.
<is-transaction-successful> – sinalizar para informar ao cliente produtor se a transação precisa ser bem-sucedida ou não.

Testando transações bem-sucedidas

A seguir estão as etapas para testar transações bem-sucedidas com o ActiveMQ:

    1. Listar filas e contagens de mensagens no console ActiveMQ
      1. Navegue até o console do Amazon MQ e escolha seu broker ActiveMQ.
      2. Faça login no ActiveMQ Web Console a partir de URLs no painel Conexões.
      3. Clique em Manage ActiveMQ broker.
      4. Forneça o nome de usuário e a senha usados para o usuário criado quando você criou o broker.
      5. Clique em Queues na barra de navegação superior.
      6. Verifique que warehouse-queue e shipping-queue não estão listadas.
    2. Execute o comando a seguir para enviar mensagens para order1 para ambas as filas com sucesso:
java -jar <path-to-jar-file>/<jar-filename> <username> <password> <ssl-endpoint> warehouse-queue shipping-queue order1 true
JSON

Substitua os espaços reservados conforme mencionado nas instruções de comando acima. Com esse comando, o exemplo de cliente produtor envia a primeira mensagem para warehouse-queue, mostra a seguinte mensagem no console e espera por 15 segundos.

Sending message: order1 to the warehouse-queue
Message: order1 is sent to the queue: warehouse-queue but not yet committed.
JSON

Durante os 15 segundos de espera, atualize o navegador e verifique que warehouse-queue está listada agora, mas não tem mensagens pendentes ou enfileiradas.

Depois de 15 segundos, o cliente produtor envia a segunda mensagem para shipping-queue, mostra a seguinte mensagem no console e espera por mais 15 segundos.

Sending message: order1 to the shipping-queue
Message: order1 is sent to the queue: shipping-queue but not yet committed.
JSON

Durante essa espera de 15 segundos, atualize a janela do navegador novamente e verifique que shipping-queue agora está listada, mas, assim como a warehouse-queue, ela não tem mensagens pendentes ou enfileiradas.

Finalmente, o cliente produtor confirma as duas mensagens e mostra:

Committing
Transaction for Message: order1 is now completely committed.
JSON
    1. Atualize o navegador e verifique se a fila do warehouse e shipping têm 1 mensagem pendente e enfileirada cada. A lista ficará como abaixo:Image shows example of queues with message count.Imagem mostrando as filas de remessa e armazém

Repita esse processo para testar mais transações bem-sucedidas.

Testando transações com falha

      1. Anote o número inicial de mensagens pendentes e enfileiradas em cada uma das filas.
      2. Execute o comando a seguir e passe false para <is-transaction-successful> para introduzir uma falha artificial.
java -jar <path-to-jar-file>/<jar-filename> <username> <password> <ssl-endpoint> warehouse-queue shipping-queue failedorder1 false
JSON

Substitua os espaços reservados conforme mencionado nas instruções iniciais do comando acima. Com esse comando, o exemplo de cliente produtor envia a primeira mensagem para a fila do depósito, mostra a seguinte mensagem no console e espera por 15 segundos.

Sending message: failedorder1 to the warehouse-queue
Message: failedorder1 is sent to the queue: warehouse-queue but not yet committed.
JSON

Durante os 15 segundos de espera, atualize o navegador e verifique se as contagens em warehouse-queue e em shipping-queue estão inalteradas.

Finalmente, o cliente introduz artificialmente uma falha, reverte a transação e mostra:

Message: failedorder1 cannot be delivered because of an unknown error. Hence the transaction is rolled back.
JSON
      1. Atualize o navegador para confirmar que o número de mensagem para ambas as filas estão inalteradas. Este exemplo começa com 1 mensagem em cada fila que permaneceu inalterada após a transação com falha.A imagem mostra um exemplo de filas de compras e depósitos com mensagens de falha.A imagem mostra um exemplo de filas de compras e depósitos com mensagens de falha.

Observe que, tanto nos cenários bem-sucedidos quanto nos mal-sucedidos, as mensagens enviadas às filas como parte de uma transação são armazenadas na memória no lado do cliente. Essas mensagens são enviadas ao broker somente quando a transação é confirmada.

Limpeza

      1. Exclua o broker executando o seguinte comando
aws mq delete-broker --broker-id <BrokerId>
JSON

Conclusão

Neste artigo você criou um broker do Amazon MQ para o ActiveMQ para a versão 5.18. Você também aprendeu sobre o novo controle de versão semântico introduzido pelo Amazon MQ. O ActiveMQ 5.18.x oferece suporte para JMS 2.0, Spring 5.3.x e atualizações de dependências. Por fim, você criou um aplicativo de exemplo usando a API JMS 2.0 mostrando os recursos transacionais do broker ActiveMQ 5.18.x.

Para saber mais sobre o Amazon MQ, visite https://thinkwithwp.com/amazon-mq/.

Este blog é uma tradução do conteúdo original em inglês (link aqui).

Biografia do autores

Paras Jain é  gerente técnico sênior de contas na Amazon Web Services (AWS).
Vinodh Kannan Sadayamuthu é arquiteto de soluções especialista sênior na Amazon Web Services (AWS).

Biografia do tradutor

Daniel Abib

Daniel Abib é Arquiteto de Soluções Sênior e Especialista em Amazon Bedrock na AWS, com mais de 25 anos trabalhando com gerenciamento de projetos, arquiteturas de soluções escaláveis, desenvolvimento de sistemas e CI/CD, microsserviços, arquitetura Serverless & Containers e especialização em Machine Learning. Ele trabalha apoiando Startups, ajudando-os em sua jornada para a nuvem.

https://www.linkedin.com/in/danielabib/

Biografia do Revisor

Eduardo Bortoluzzi é Arquiteto de Aplicações Cloud Sênior na equipe de AWS Professional Services e especialista em soluções Serverless, com mais de 16 anos atuando em arquiteturas de soluções em nuvem. Ele trabalha acelerando empresas de serviços financeiros a criarem soluções resilientes e escaláveis na AWS.