Comunicação assíncrona entre microsserviços: filas

Por Felipe Barbosa, 20/02/2023

Microservices

A motivação e o projeto

Todos os posts que são publicados aqui no blog são também compartilhados no Linkedin. Isso é uma maneira de sinalizar aos possíveis interessados que um novo conteúdo está disponível. Uma outra maneira de fazer isso seria implementar SSR Feed, mas poucas pessoas fora e até dentro da bolha tech estão familiarizadas com essa ferramenta.

O problema é que o Linkedin provavelmente não é a ferramenta primária de consumo de conteúdo técnico da maioria das pessoas. E mesmo que seja, é bastante possível que essas pessoas não acessem a rede todos os dias.

Entretanto, uma ferramenta que provavelmente é acessada todos os dias pela maioria das pessoas é o e-mail. Então resolvi criar um sistema de inscrição para que as pessoas que acompanham o blog pudessem ser notificadas por e-mail toda vez que um conteúdo novo fosse adicionado. Essa também era uma ótima desculpa para pôr em prática alguns conceitos de arquitetura design de software que eu vinha estudando, além de ser um ótimo candidato para criação de um microsserviço, que foi um dos alvos de estudo que eu elenquei para 2023.

Fluxo de uso

O serviço é simples e pode ser dividido em duas partes.

A primeira parte do serviço expõe uma API para a criação e confirmação de uma inscrição. O processo de confirmação acontece via e-mail e garante que usuários maliciosos não vão cadastrar e-mails aleatórios, poluindo o serviço com e-mails inexistentes ou que não estão em uso.

Essa primeira parte é bastante simples, porém foi, como mencionado antes, uma ótima oportunidade para testar e pôr em prática meus conhecimentos de arquitetura de software. DDD, Clean Architecture, testes, foram todos incluídos no projeto.

A segunda parte envolveu conceitos realmente novos para mim e bastante interessantes que estavam no meu mapa para serem explorados.

Comunicação assíncrona de microsserviços

Uma vez que um e-mail foi cadastrado e confirmado a ideia é a de que o usuário esteja apto para receber e-mails na sua caixa de entrada toda vez que um conteúdo novo for adicionado.

Para tanto, o serviço de gerenciamento de conteúdo precisa se comunicar com o recém-criado serviço quando um conteúdo novo for adicionado, para que então os e-mails possam ser disparados por ele.

Essa comunicação poderia ser implementada de forma síncrona: o serviço de e-mails poderia expor uma rota que poderia ser chamada para disparar e-mails para todos os recipientes confirmados.

Entretanto, o que aconteceria se essa comunicação falhasse? Se por qualquer motivo o serviço de e-mails estivesse indisponível no momento, essa “ordem” de envio de e-mails seria perdida.

Seria possível implementar uma lógica de re-tentativa no lado da API de gerenciamento, porém não seria algo muito elegante, principalmente porque todos os serviços mencionados aqui estão em uma ambiente serverless, especificamente na AWS Lambda. O que fazer então?

A solução: filas

Note que o tipo de comunicação descrito anteriormente é síncrono: um serviço fala diretamente com o outro e ambos precisam estar disponíveis naquele instante para se comunicar. O problema acontece quando possíveis erros de comunicação aparecem no caminho. Uma possível solução é implementar uma comunicação assíncrona usando filas, que funcionam como um intermediador da comunicação entre serviços.

Ao invés de se comunicarem diretamente, mensagens que um serviço quer fazer chegar a outro são colocadas na fila. O segundo serviço pode, então, procurar por mensagens na mesma e consumi-las. Note que esse é um padrão de comunicação assíncrono: se por acaso o serviço responsável por processar as mensagens estiver indisponível no momento, as mensagens continuam retidas na fila e disponíveis para serem processadas assim que o serviço estiver novamente de pé.

Esse modelo de comunicação dá um nível de confiabilidade muito grande e robusto para a comunicação desses serviços.

Implementação

Na AWS, o serviço básico de filas chama-se SQS: Simple Queue Service. E é bastante simples integrá-lo a uma função Lambda.

Funciona da seguinte forma:

  1. Cria-se uma fila e uma função Lambda.

  2. Configura-se a função Lambda para ter permissões de consumir mensagens da fila.

  3. Adiciona-se mensagens da fila como um trigger, um acionador da função Lambda e... pronto.

Se a função Lambda conseguir processar com sucesso a mensagem consumida, o serviço automaticamente exclui a mensagem da fila. Se não, a função tenta processar novamente com intervalos cada vez maiores. Uma estratégia de logging e error handling é necessária para fazer com que as coisas fluam de forma suave, mas não é nada particularmente sofisticado.

Conclusão

Comunicação assíncrona entre serviços usando filas é uma maneira bastante robusta de implementar microsserviços. É possível usar outras tecnologias para fazer isso, como o Redis, para ter maior flexibilidade e minimizar a possibilidade de ficar preso a um provedor como AWS.

Seja como for, é um padrão de arquitetura bastante poderoso.

Agora que você já sabe como o sistema funciona, aproveite e se inscreva abaixo para ser notificado quando houver conteúdo novo!

Vejo vocês na próxima, cheers!

Gostando até aqui? ✍️

Receba atualizações de conteúdo diretamente na sua caixa de entrada!