Padrão de Transação Compensatória

Use este padrão para reverter o trabalho quando uma ou mais etapas falham em uma operação com consistência eventual. Aplicações alojadas na cloud que implementam processos e fluxos de trabalho empresariais complexos utilizam frequentemente operações que seguem o modelo de consistência eventual.

Contexto e problema

As aplicações cloud modificam frequentemente dados que estão distribuídos por várias fontes de dados em diferentes localizações geográficas. Para evitar contendas e melhorar o desempenho num ambiente distribuído, as aplicações devem implementar consistência eventual em vez de uma consistência transacional forte. No modelo de consistência eventual, uma operação de negócios típica consiste em uma série de etapas separadas. Durante estes passos, a visão geral do estado do sistema pode ser inconsistente. Mas o sistema deve voltar a ser consistente quando todos os passos terminam.

Lidar com falhas de etapas apresenta um desafio fundamental no modelo de consistência final. Após uma falha, pode ser necessário desfazer o trabalho das etapas operacionais concluídas. No entanto, nem sempre pode reverter os dados porque outras instâncias de aplicação concorrentes podem alterar os dados. Mesmo quando instâncias concorrentes não alteram os dados, pode ser mais complexo desfazer um passo do que restaurar o estado original. Pode ser necessário aplicar regras específicas do negócio. Para um exemplo, veja o exemplo do site de viagens.

Quando uma operação que implementa consistência eventual abrange vários repositórios de dados, deve aceder a cada armazenamento de dados para desfazer as alterações. Para evitar que o sistema permaneça inconsistente, deve reverter fiavelmente o trabalho em cada base de dados.

Uma operação que implementa consistência eventual nem sempre armazena os seus dados afetados numa base de dados. Por exemplo, num ambiente de arquitetura orientada a serviços (SOA), uma operação pode invocar uma ação num serviço e alterar o estado que o serviço mantém. Para desfazer a operação, também deverá desfazer esta alteração de estado, o que poderá envolver invocar novamente o serviço para reverter os efeitos da primeira ação.

Solução

Implementar uma transação compensatória que anule os efeitos dos passos concluídos na operação original. Pode pensar que pode simplesmente restaurar o sistema ao seu estado original, mas esta abordagem pode sobrescrever alterações de outras instâncias de aplicação concorrentes. Em vez disso, a transação compensatória deve contabilizar de forma inteligente o trabalho concorrente. Este processo é geralmente específico da aplicação e depende da operação original.

Pode usar um fluxo de trabalho para implementar uma operação eventualmente consistente que exija compensação. À medida que a operação original é executada, o sistema regista informações sobre cada passo e como o desfazer. Se a operação falhar, o fluxo de trabalho rebobina os passos concluídos e inverte cada passo.

Diagrama que mostra os passos para criar um itinerário e os passos da transação compensatória que cancelam o itinerário.

Embora cada passo seja uma ação separada, juntos formam uma operação eventualmente consistente. O sistema deve realizar as etapas e as correspondentes operações de anulação para cada etapa. Se o cliente cancelar, estas operações de reversão podem ser executadas como uma transação compensatória.

Uma falha de um único passo nem sempre exige que revertas todo o sistema usando uma transação compensatória. Por exemplo, num cenário de um site de viagens, um cliente reserva voos F1, F2 e F3 mas não consegue reservar um quarto no hotel H1. Oferecer ao cliente um quarto noutro hotel é preferível a cancelar os voos. O cliente ainda pode optar por cancelar, o que desencadeia a transação compensatória para anular as reservas de voo. No entanto, é o cliente que deve tomar essa decisão, não o sistema. Quando as decisões são de grande impacto ou difíceis de automatizar de forma fiável, inclua uma pessoa no processo de tomada de decisão.

Considere estes pontos importantes:

  • Uma transação compensatória pode não precisar de desfazer o trabalho exatamente na ordem inversa da operação original.

  • É possível realizar alguns passos de desfazer em paralelo.

  • Pode ser necessário aplicar regras específicas do negócio. Por exemplo, cancelar uma reserva de voo pode não dar direito ao reembolso total do cliente.

Esta abordagem é semelhante ao padrão de transações distribuídas da Saga.

As transações compensadoras acabam por ser operações consistentes e podem falhar. O sistema deve registar o progresso para poder retomar a transação compensatória a partir do ponto de falha. Um passo pode ser executado várias vezes quando tentado novamente, por isso desenha cada passo como um comando idempotente.

Por vezes, a intervenção manual é a única forma de recuperar de um passo falhado. Nestas situações, o sistema deve emitir um alerta que inclua informações detalhadas sobre a razão da falha.

Problemas e considerações

Considere os seguintes pontos ao decidir como implementar este padrão:

  • Pode não ser fácil determinar quando uma etapa de uma operação que implementa uma eventual consistência falha. Um passo pode não falhar imediatamente, mas sim ser bloqueado. Pode ser necessário implementar um mecanismo de timeout.

  • Não é fácil generalizar a lógica de compensação. Uma transação compensatória é específica da aplicação. Baseia-se na aplicação ter informação suficiente para desfazer os efeitos de cada etapa numa operação falhada.

  • As transações compensatórias nem sempre funcionam. Defina os passos numa transação compensatória como comandos idempotentes para que possa repeti-los caso a transação compensatória falhe.

  • A infraestrutura que lida com as etapas deve atender aos seguintes critérios:

    • É resiliente tanto na operação original como na transação compensatória.

    • Não perde a informação necessária para compensar um passo falhado.

    • Monitoriza de forma fiável o progresso da lógica de compensação. As transações compensadoras são executadas após a confirmação das operações originais, e outras transações podem alterar estados intermediários. Por isso, certifique-se de que consegue correlacionar e auditar tanto a operação original como a sua compensação de ponta a ponta.

  • Uma transação de compensação não necessariamente retorna os dados do sistema ao seu estado no início da operação original. Em vez disso, a transação compensa pelo trabalho que a operação conseguiu completar com sucesso antes de falhar.

  • Os passos compensatórios da transação nem sempre revertem a operação original na ordem exatamente oposta. Por exemplo, se um armazenamento de dados for mais sensível a inconsistências do que outro, desfaça primeiro as alterações desse armazenamento.

  • Algumas medidas podem ajudar a melhorar as taxas de sucesso. Pode colocar um bloqueio de curto prazo com um timeout em cada recurso necessário para completar uma operação. Pode adquirir esses recursos antecipadamente e depois realizar o trabalho apenas depois de adquirir todos os recursos. Finalize todas as ações antes que os bloqueios expirem.

  • A lógica de repetição, que considera mais erros como transitórios, pode ajudar a minimizar falhas que desencadeiam uma transação compensatória. Quando um passo numa operação que implementa consistência eventual falha, trate-o como uma exceção transitória e tente novamente o passo. Só pare a operação e ative a compensação se o passo falhar repetidamente ou se não for possível recuperá-lo. Para mais informações sobre estratégias de nova tentativa, consulte Tratamento de falhas transitórias.

  • Quando implementa uma transação compensatória, enfrenta muitos desafios semelhantes aos da implementação da consistência eventual. Para obter mais informações, consulte Minimizar a coordenação.

  • Defina pontos claros de não retorno e passos irreversíveis. Em fluxos de trabalho complexos, não se pode desfazer de forma segura ou significativa algumas operações, como efeitos secundários externos ou ações legalmente vinculativas. Identifique passos compensáveis versus irreversíveis. Projetar o fluxo de trabalho para que passos irreversíveis ocorram apenas depois de todas as validações críticas terem sido bem-sucedidas.

Quando utilizar este padrão

Utilize este padrão quando:

  • Uma operação empresarial abrange múltiplos passos, serviços ou armazenamentos de dados e deve ser desfeita caso uma etapa posterior falhe. Este cenário ocorre frequentemente em fluxos de trabalho de longa duração que seguem um modelo de consistência eventual e não podem depender de transações atómicas.

  • A recuperação de falhas frequentemente requer uma lógica de domínio específica, em vez de uma simples reversão de dados. Use ações compensatórias quando for necessário desfazer trabalho e aplicar regras de negócio, como cancelar reservas ou emitir reembolsos parciais.

Este padrão pode não ser adequado quando:

  • As operações podem ser tentadas novamente em segurança e a maioria das falhas é transitória. A lógica de retentativa sozinha é frequentemente suficiente nestes casos, e as transações compensatórias acrescentam complexidade desnecessária.

  • O sistema não tolera inconsistências temporárias, ou a compensação não pode restaurar de forma fiável um estado válido. Use mecanismos fortes de consistência ou transações atómicas em todas as etapas.

Design da carga de trabalho

Avalie como utilizar a Transação Compensatória no design de uma carga de trabalho para abordar os objetivos e princípios abordados nos pilares Azure Well-Architected Framework. A tabela a seguir fornece orientação sobre como esse padrão suporta as metas de cada pilar.

Pilar Como esse padrão suporta os objetivos do pilar
As decisões de projeto de confiabilidade ajudam sua carga de trabalho a se tornar resiliente ao mau funcionamento e garantem que ela se recupere para um estado totalmente funcional após a ocorrência de uma falha. As ações de compensação resolvem avarias em caminhos críticos de carga de trabalho utilizando processos como reverter diretamente alterações de dados, quebrar bloqueios de transações ou até executar comportamentos nativos do sistema para reverter o efeito.

- RE:02 Fluxos críticos
- RE:09 Recuperação de desastres

Se este padrão introduzir compensações dentro de um pilar, considere-as em relação aos objetivos dos outros pilares.

Exemplo

O diagrama seguinte mostra uma implementação prática do Azure do padrão Compensating Transaction. Outras implementações também podem funcionar para os requisitos da tua carga de trabalho. Um orquestrador que corre no Azure Container Apps coordena cada etapa de um fluxo de trabalho de longa duração enviando comandos através do Azure Service Bus. À medida que cada passo em frente tem sucesso, o orquestrador regista tanto o estado de execução como a ação compensatória correspondente no Azure Cosmos DB, para que o fluxo de trabalho possa ser retomado, correlacionado e auditado.

Diagrama que mostra uma implementação Azure do padrão de Transação Compensadora.

Este modelo usa tentativas múltiplas primeiro para manter o progresso. Se um passo falhar, o orquestrador aplica lógica de nova tentativa para falhas transitórias e tenta prosseguir com a operação original. A compensação é invocada apenas quando o progresso se torna impossível, como quando as tentativas de novo se esgotam ou quando a falha é classificada como não transitória.

As regras específicas do negócio também podem preferir progresso futuro em vez de compensação imediata. Se um passo falhar, o orquestrador pode selecionar um caminho alternativo, como substituir por um serviço equivalente ou opção de recurso, em vez de reverter o fluxo de trabalho. Para casos de impacto elevado ou ambíguos, pode suspender o fluxo de trabalho para análise humana antes de decidir se continua por um caminho alternativo ou aciona o mecanismo de compensação. Esta abordagem trata a compensação como último recurso e permite que as regras do domínio guiem as decisões de recuperação.

Numa sequência típica, o orquestrador envia mensagens de passo através do Service Bus (passos 1 e 2), recebe resultados bem-sucedidos e armazena metadados de encaminhamento e compensação no Azure Cosmos DB.

Pode ativar a compensação de duas formas:

  • Quando uma etapa posterior da mesma carga falha e tens de desfazer etapas anteriores bem-sucedidas. Esta compensação pode ocorrer imediatamente quando um passo devolve um erro de negócio, como uma falha na validação de regras, ou após as tentativas técnicas serem esgotadas e a mensagem ser movida para a fila de letras mortas.

  • Quando um cliente subsequente solicita explicitamente o cancelamento de uma operação concluída.

Em qualquer dos casos, o orquestrador lê os registos de compensação armazenados e envia comandos de compensação para o serviço correspondente. Se uma etapa de compensação falhar temporariamente, as tentativas do Service Bus podem completá-la sem escalar o incidente.

Se as tentativas repetidas continuarem a falhar, o Service Bus move a mensagem para uma fila de letras mortas e preserva os detalhes da falha. O orquestrador, ou um processador dedicado de dead-letters, levanta um alerta e emite telemetria estruturada, incluindo a razão de falha e IDs de correlação, para o Azure Monitor e Log Analytics, que podem ser exibidos no Application Insights. Este percurso operacional ajuda as equipas a diagnosticar falhas, determinar a necessidade de intervenção manual e manter a rastreabilidade tanto entre os fluxos originais como os compensadores.

O fluxo de trabalho pode iniciar automaticamente a compensação para condições claras e de baixo risco ou fazer uma pausa para revisão humana quando a situação é ambígua, de alto impacto ou requer uma decisão manual.

Use identidades geridas e autorização baseada no Microsoft Entra ID entre componentes para evitar segredos partilhados e garantir o acesso com privilégios mínimos. Ao criar um diagrama de referência simplificado, trate estes controlos de identidade e autorização como preocupações de implementação base, em vez de etapas explícitas de fluxo. Mantém o diagrama focado na orquestração, nova tentativa, compensação e gestão de erros.

  • Considerações de dados para microserviços: Saiba por que a consistência eventual e a falha parcial são inerentes aos sistemas distribuídos. O padrão de Transação Compensadora fornece um mecanismo concreto para lidar com essas falhas quando as operações abrangem múltiplos serviços.

  • Padrão de Outbox Transacional com Azure Cosmos DB: Use este padrão quando as transações compensadoras precisam publicarem eventos ou comandos de forma fiável. Ajuda a garantir que as alterações de estado e as mensagens são registadas de forma atómica, o que previne a perda de mensagens.

  • Desenhe para a auto-cura: Use transações compensadoras como parte de uma abordagem de auto-cura para as suas aplicações.

  • Padrão Supervisor de Agente Agendador: Use este padrão para implementar sistemas resilientes que realizem operações de negócio entre serviços e recursos distribuídos. Estes sistemas, por vezes, precisam de transações compensatórias para desfazer o trabalho.

  • Padrão de repetição: Use este padrão para lidar com falhas transitórias e minimizar a necessidade de transações compensadoras.

  • Padrão de transações distribuídas Saga: Use este padrão para gerir a consistência dos dados entre microserviços em transações distribuídas. A Saga utiliza transações compensatórias para recuperação de falhas.

  • Padrão Pipes and Filters: Use este padrão com o padrão Compensating Transaction como alternativa às transações distribuídas quando decompor tarefas complexas em etapas reutilizáveis.