Implementar o padrão de saga com tecnologia sem servidor usando o AWS Step Functions - Recomendações da AWS

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Implementar o padrão de saga com tecnologia sem servidor usando o AWS Step Functions

Criado por Tabby Ward (AWS), Rohan Mehta (AWS) e Rimpy Tewani (AWS)

Ambiente: PoC ou piloto

Tecnologias: modernização; tecnologia sem servidor; nativo de nuvem

Workload: código aberto

Serviços da AWS: Amazon API Gateway; Amazon DynamoDB; AWS Lambda; Amazon SNS; AWS Step Functions

Resumo

Em uma arquitetura de microsserviços, o objetivo principal é criar componentes desacoplados e independentes para promover agilidade, flexibilidade e menor tempo de comercialização de seus aplicativos. Como resultado do desacoplamento, cada componente de microsserviço tem sua própria camada de persistência de dados. Em uma arquitetura distribuída, as transações comerciais podem abranger vários microsserviços. Como esses microsserviços não podem usar uma única transação de atomicidade, consistência, isolamento e durabilidade (ACID), você pode acabar com transações parciais. Nesse caso, alguma lógica de controle é necessária para desfazer as transações que já foram processadas. O padrão de saga distribuída é normalmente usado para essa finalidade. 

O padrão saga é um padrão de gerenciamento de falhas que ajuda a estabelecer a consistência em aplicativos distribuídos e coordena as transações entre vários microsserviços para manter a consistência de dados. Quando você usa o padrão de saga, cada serviço que realiza uma transação publica um evento que aciona serviços subsequentes para realizar a próxima transação na cadeia. Isso continua até que a última transação na cadeia seja concluída. Se uma transação comercial falhar, a saga orquestra uma série de transações compensatórias que desfazem as alterações feitas pelas transações anteriores.

Esse padrão demonstra como automatizar a configuração e a implantação de um aplicativo de amostra (que lida com reservas de viagens) com tecnologias sem servidor, como AWS Step Functions, AWS Lambda e Amazon DynamoDB. O aplicativo de amostra também usa o Amazon API Gateway e o Amazon Simple Notification Service (Amazon SNS) para implementar um coordenador de execução da saga. O padrão pode ser implantado com uma estrutura de infraestrutura como código (IaC), como o AWS Cloud Development Kit (AWS CDK), o AWS Serverless Application Model (AWS SAM) ou o Terraform.

Para obter mais informações sobre o padrão da saga e outros padrões de persistência de dados, consulte o guia Habilitar a persistência de dados em microsserviços no site de Recomendações da AWS.

Pré-requisitos e limitações

Pré-requisitos

  • Uma conta AWS ativa

  • Permissões para criar uma CloudFormation pilha da AWS. Para obter mais informações, consulte Controle de acesso na CloudFormation documentação.

  • Estrutura de IaC de sua escolha (AWS CDK, AWS SAM ou Terraform) configurada com sua conta da AWS para que você possa usar a CLI da estrutura para implantar o aplicativo.

  • NodeJS, usado para criar o aplicativo e executá-lo localmente.

  • Um editor de código de sua escolha (como Visual Studio Code, Sublime ou Atom).

Versões do produto

Limitações

O fornecimento de eventos é uma forma natural de implementar o padrão de orquestração da saga em uma arquitetura de microsserviços em que todos os componentes estão com acoplamento fraco e não têm conhecimento direto uns dos outros. Se sua transação envolver um pequeno número de etapas (três a cinco), o padrão da saga pode ser uma ótima opção. No entanto, a complexidade aumenta com o número de microsserviços e o número de etapas. 

Testar e depurar podem se tornar difíceis quando você usa esse design, porque você precisa ter todos os serviços em execução para simular o padrão da transação.

 

Arquitetura

Arquitetura de destino

A arquitetura proposta usa o AWS Step Functions para criar um padrão de saga para reservar voos, reservar aluguéis de carros e processar pagamentos de férias.

O diagrama de fluxo de trabalho a seguir ilustra o fluxo típico do sistema de reserva de viagens. O fluxo de trabalho consiste em reservar viagens aéreas (“ReserveFlight”), reservar um carro (“ReserveCarRental”), processar pagamentos (“ProcessPayment”), confirmar reservas de voos (“ConfirmFlight”) e confirmar aluguéis de carros (“”), seguido por uma notificação de sucesso quando essas etapas forem concluídas. ConfirmCarRental No entanto, se o sistema encontrar algum erro na execução de qualquer uma dessas transações, ele começará a falhar para trás. Por exemplo, um erro no processamento do pagamento (“ProcessPayment”) aciona um reembolso (“RefundPayment”), que então aciona o cancelamento do carro e do voo alugados (“CancelRentalReservation” e “CancelFlightReservation”), o que encerra toda a transação com uma mensagem de falha.

Esse padrão implanta funções do Lambda separadas para cada tarefa destacada no diagrama, bem como três tabelas do DynamoDB para voos, aluguel de carros e pagamentos. Cada função do Lambda cria, atualiza ou exclui as linhas nas respectivas tabelas do DynamoDB, dependendo se uma transação é confirmada ou revertida. O padrão usa o Amazon SNS para enviar mensagens de texto (SMS) aos assinantes, notificando-os sobre transações fracassadas ou bem-sucedidas. 

Automação e escala

Você pode criar a configuração para essa arquitetura usando uma das estruturas do IaC. Para se conectar no IaC de sua preferência, use um dos links a seguir.

Ferramentas

Serviços da AWS

  • O AWS Step Functions é um serviço de orquestração de tecnologia sem servidor que permite combinar funções do AWS Lambda e outros serviços da AWS para criar aplicações essenciais aos negócios. A partir do console gráfico do Step Functions, você vê o fluxo de trabalho do seu aplicativo como uma série de etapas orientadas por eventos.

  • O Amazon DynamoDB é um serviço de banco de dados NoSQL totalmente gerenciado que fornece uma performance rápida e previsível com escalabilidade integrada. Use o DynamoDB para criar uma tabela do banco de dados que possa armazenar e recuperar qualquer quantidade de dados e atender qualquer nível de tráfego solicitado.

  • O AWS Lambda é um serviço de computação que permite que você execute o código sem provisionar ou gerenciar servidores. O Lambda executa o código somente quando necessário e dimensiona automaticamente, desde algumas solicitações por dia até milhares por segundo.

  • O Amazon API Gateway é um serviço da AWS para criar, publicar, manter, monitorar e proteger REST, HTTP e WebSocket APIs em qualquer escala.

  • O Amazon Simple Notification Service (Amazon SNS) é um serviço gerenciado que fornece entrega de mensagens de publicadores para assinantes.

  • O AWS Cloud Development Kit (AWS CDK) é uma estrutura de desenvolvimento de software para definir seus recursos de aplicativos em nuvem usando linguagens de programação conhecidas TypeScript, como Python JavaScript, Java e C#/.Net.

  • O AWS Serverless Application Model (AWS SAM) é uma estrutura de código aberto para a criação de aplicativos com tecnologia sem servidor. Ele fornece sintaxe abreviada para expressar funções, APIs, bancos de dados e mapeamentos da origem do evento.

Código

O código de um aplicativo de amostra que demonstra o padrão da saga, incluindo o modelo IaC (AWS CDK, AWS SAM ou Terraform), as funções do Lambda e as tabelas do DynamoDB, pode ser encontrado nos links a seguir. Siga as instruções no primeiro epic para instalá-los.

Épicos

TarefaDescriçãoHabilidades necessárias

Instale os pacotes NPM.

Crie um novo diretório, navegue até esse diretório em um terminal e clone o GitHub repositório de sua escolha na seção Código anterior nesse padrão.

Na pasta raiz que contém o arquivo package.json, execute o comando a seguir para baixar e instalar todos os pacotes do Node Package Manager (NPM):

npm install
Desenvolvedor e arquiteto de nuvem

Compile scripts.

Na pasta raiz, execute o comando a seguir para instruir o TypeScript transpilador a criar todos os arquivos necessários: JavaScript

npm run build
Desenvolvedor e arquiteto de nuvem

Observe as alterações e recompile.

Na pasta raiz, execute o comando a seguir em uma janela de terminal separada para observar as alterações no código e compilar o código quando detectar uma alteração:

npm run watch
Desenvolvedor e arquiteto de nuvem

Execute testes de unidade (somente AWS CDK).

Se você estiver usando o AWS CDK, na pasta raiz, execute o seguinte comando para realizar os testes de unidade do Jest:

npm run test
Desenvolvedor e arquiteto de nuvem
TarefaDescriçãoHabilidades necessárias

Implante a pilha de demonstração na AWS.

Importante: o aplicativo é independente da região da AWS. Se você usar um perfil, deverá declarar a região explicitamente no perfil da AWS Command Line Interface (AWS CLI) ou por meio de variáveis de ambiente da AWS CLI.

Na pasta raiz, execute o comando a seguir para criar um conjunto de implantação e implantá-lo na conta e região padrão da AWS.

AWS CDK:

cdk bootstrap cdk deploy

AWS SAM:

sam build sam deploy --guided

Terraform:

terraform init terraform apply

Esta etapa pode demorar vários minutos para que seja concluída. Esse comando usa as credenciais padrão que foram configuradas para a AWS CLI.

Observe o URL do API Gateway que é exibida no console após a conclusão da implantação. Você precisará dessas informações para testar o fluxo de execução da saga.

Desenvolvedor e arquiteto de nuvem

Compare a pilha implantada com o estado atual.

Na pasta raiz, execute o comando a seguir para comparar a pilha implantada com o estado atual depois de fazer alterações no código-fonte:

AWS CDK:

cdk diff

AWS SAM:

sam deploy

Terraform:

terraform plan
Desenvolvedor e arquiteto de nuvem
TarefaDescriçãoHabilidades necessárias

Teste o fluxo de execução da saga.

Navegue até o URL do API Gateway que você anotou na etapa anterior, ao implantar a pilha. Esse URL aciona a inicialização da máquina de estado. Para obter mais informações sobre como manipular o fluxo da máquina de estado passando parâmetros de URL diferentes, consulte a seção Informações adicionais.

Para ver os resultados, faça login no Console de Gerenciamento da AWS e navegue até o console do Step Functions. Aqui, você pode ver cada passo da máquina de estado da saga. Você também pode visualizar a tabela do DynamoDB para ver os registros inseridos, atualizados ou excluídos. Se você atualizar a tela com frequência, poderá observar a mudança do status da transação de pending para confirmed

Você pode assinar o tópico do SNS atualizando o código no arquivo stateMachine.ts com seu número de telefone celular para receber mensagens SMS em caso de reservas bem-sucedidas ou malsucedidas. Para obter mais informações, consulte Amazon SNS na seção Informações adicionais.

Desenvolvedor e arquiteto de nuvem
TarefaDescriçãoHabilidades necessárias

Limpar os recursos.

Para limpar os recursos implantados para esse aplicativo, você pode usar um dos seguintes comandos.

AWS CDK:

cdk destroy

AWS SAM:

sam delete

Terraform:

terraform destroy
Desenvolvedor de aplicativos, arquiteto de nuvem

Recursos relacionados

Artigos técnicos

Documentação do serviço da AWS

Tutoriais

Mais informações

Código

Para fins de teste, esse padrão implanta o API Gateway e uma função do Lambda de teste que aciona a máquina de estado Step Functions. Com o Step Functions, você pode controlar a funcionalidade do sistema de reserva de viagens passando um run_type parâmetro para simular falhas em “ReserveFlight,” “ReserveCarRental,” “ProcessPayment,” “ConfirmFlight,” e “”ConfirmCarRental.

A função do Lambda saga (sagaLambda.ts) recebe a entrada dos parâmetros de consulta no URL do API Gateway, cria o seguinte objeto JSON e o passa para o Step Functions para execução:

let input = { "trip_id": tripID, //  value taken from query parameter, default is AWS request ID "depart_city": "Detroit", "depart_time": "2021-07-07T06:00:00.000Z", "arrive_city": "Frankfurt", "arrive_time": "2021-07-09T08:00:00.000Z", "rental": "BMW", "rental_from": "2021-07-09T00:00:00.000Z", "rental_to": "2021-07-17T00:00:00.000Z", "run_type": runType // value taken from query parameter, default is "success" };

Você pode experimentar diferentes fluxos da máquina de estado Step Functions passando os seguintes parâmetros de URL:

  • Execução bem-sucedida ─ https://{api gateway url}

  • Falha no voo de reserva ─ https://{api gateway url}? Tipo de execução = failFlightsReservation

  • Confirme a falha do voo ─ https://{api gateway url}? Tipo de execução = failFlightsConfirmation

  • Falha na reserva do aluguel de carros ─ https://{api gateway url}? RunType= Reserva failCarRental

  • Confirme a falha no aluguel do carro ─ https://{api gateway url}? RunType= Confirmação failCarRental

  • Falha no processo de pagamento ─ https://{api gateway url}?runType=failPayment

  • Passe um ID de viagem ─ https://{api gateway url}?tripID={por padrão, o ID da viagem será o ID da solicitação da AWS}

Modelos IaC

Os repositórios vinculados incluem modelos de IaC que você pode usar para criar toda a amostra do aplicativo de reserva de viagens.

Tabelas do DynamoDB

Aqui estão os modelos de dados para as tabelas de voos, aluguéis de carros e pagamentos.

Flight Data Model: var params = { TableName: process.env.TABLE_NAME, Item: { 'pk' : {S: event.trip_id}, 'sk' : {S: flightReservationID}, 'trip_id' : {S: event.trip_id}, 'id': {S: flightReservationID}, 'depart_city' : {S: event.depart_city}, 'depart_time': {S: event.depart_time}, 'arrive_city': {S: event.arrive_city}, 'arrive_time': {S: event.arrive_time}, 'transaction_status': {S: 'pending'} } }; Car Rental Data Model: var params = { TableName: process.env.TABLE_NAME, Item: { 'pk' : {S: event.trip_id}, 'sk' : {S: carRentalReservationID}, 'trip_id' : {S: event.trip_id}, 'id': {S: carRentalReservationID}, 'rental': {S: event.rental}, 'rental_from': {S: event.rental_from}, 'rental_to': {S: event.rental_to}, 'transaction_status': {S: 'pending'} } }; Payment Data Model: var params = { TableName: process.env.TABLE_NAME, Item: { 'pk' : {S: event.trip_id}, 'sk' : {S: paymentID}, 'trip_id' : {S: event.trip_id}, 'id': {S: paymentID}, 'amount': {S: "750.00"}, // hard coded for simplicity as implementing any monetary transaction functionality is beyond the scope of this pattern 'currency': {S: "USD"}, 'transaction_status': {S: "confirmed"} } };

Funções do Lambda

As seguintes funções serão criadas para suportar o fluxo e a execução da máquina de estado no Step Functions:

  • Reservar voos: insere um registro na tabela de voos do DynamoDB com um transaction_status de pending, para reservar um voo.

  • Confirmar voo: atualiza o registro na tabela de voos do DynamoDB, para definir transaction_status como confirmed, para confirmar o voo.

  • Cancelar reserva de voos: exclui o registro da tabela de voos do DynamoDB para cancelar o voo pendente.

  • Reserve locações de veículos: insere um registro na tabela do CarRentals DynamoDB com transaction_status um de, para reservar um aluguel pending de carro.

  • Confirmar locação de veículos: atualiza o registro na tabela do CarRentals DynamoDB, para transaction_status definir como, confirmed para confirmar o aluguel do carro.

  • Cancelar reserva de aluguel de carro: exclui o registro da tabela do CarRentals DynamoDB para cancelar o aluguel de carro pendente.

  • Processar pagamento: insere um registro na tabela de pagamentos do DynamoDB para o pagamento.

  • Cancelar pagamento: exclui o registro do pagamento da tabela de pagamentos do DynamoDB.

Amazon SNS

O aplicativo de amostra cria o tópico e a assinatura a seguir para enviar mensagens SMS e notificar o cliente sobre reservas bem-sucedidas ou malsucedidas. Se você quiser receber mensagens de texto enquanto testa o aplicativo de amostra, atualize a assinatura de SMS com seu número de telefone válido no arquivo de definição da máquina de estado.

Trecho do AWS CDK (adicione o número de telefone na segunda linha do código a seguir):

const topic = new  sns.Topic(this, 'Topic'); topic.addSubscription(new subscriptions.SmsSubscription('+11111111111')); const snsNotificationFailure = new tasks.SnsPublish(this ,'SendingSMSFailure', { topic:topic, integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, message: sfn.TaskInput.fromText('Your Travel Reservation Failed'), });   const snsNotificationSuccess = new tasks.SnsPublish(this ,'SendingSMSSuccess', { topic:topic, integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, message: sfn.TaskInput.fromText('Your Travel Reservation is Successful'), });

Trecho do AWS SAM (substitua as strings +1111111111 pelo seu número de telefone válido):

StateMachineTopic11111111111: Type: 'AWS::SNS::Subscription' Properties: Protocol: sms TopicArn: Ref: StateMachineTopic Endpoint: '+11111111111' Metadata: 'aws:sam:path': SamServerlessSagaStack/StateMachine/Topic/+11111111111/Resource

Trecho do Terraform (substitua a string +111111111 pelo seu número de telefone válido):

resource "aws_sns_topic_subscription" "sms-target" { topic_arn = aws_sns_topic.topic.arn protocol = "sms" endpoint = "+11111111111" }

Reservas bem-sucedidas

O fluxo a seguir ilustra uma reserva bem-sucedida com “ReserveFlight,” “ReserveCarRental,” e “ProcessPayment” seguidos por “ConfirmFlight” e “”ConfirmCarRental. O cliente é notificado sobre a reserva bem-sucedida por meio de mensagens SMS enviadas ao assinante do tópico do SNS.

Reservas malsucedidas

Esse fluxo é um exemplo de falha no padrão da saga. Se, após a reserva de voos e aluguel de carros, “ProcessPayment” falhar, as etapas serão canceladas na ordem inversa.  As reservas são liberadas e o cliente é notificado da falha por meio de mensagens SMS que são enviadas ao assinante do tópico do SNS.