Melhores práticas de processamento de falhas transitórias

Todas as aplicações que comunicam com serviços e recursos remotos devem detetar e recuperar de falhas transitórias. Este requisito é especialmente verdadeiro para aplicações que correm na cloud. Devido à natureza do ambiente cloud e à conectividade pela internet, é provável que a sua aplicação encontre falhas transitórias com mais frequência. Falhas transitórias incluem a perda momentânea da conectividade de rede a componentes e serviços, a indisponibilidade temporária de um serviço e os time-outs que ocorrem quando um serviço está ocupado. Estas falhas normalmente resolvem-se sozinhas sem intervenção, pelo que a ação é provável de ter sucesso se a aplicação a tentar novamente após um atraso adequado.

O tratamento de falhas transitórias é uma técnica chave de resiliência dentro do pilar de Fiabilidade do Azure Well-Architected Framework. Se detetar e recuperar falhas transitórias ao nível da aplicação, ajuda a prevenir falhas em cascata que possam desencadear procedimentos mais amplos de resposta a incidentes ou recuperação de desastres (DR ). Uma gestão eficaz de falhas transitórias ajuda a sua carga de trabalho a tolerar perturbações rotineiras e a manter a disponibilidade sem escalar para procedimentos de recuperação ao nível da infraestrutura.

Por que ocorrem falhas transitórias na nuvem?

As falhas transitórias podem ocorrer em qualquer ambiente, em qualquer plataforma ou sistema operativo e em qualquer tipo de aplicação. Para soluções que correm em infraestrutura local, o hardware redundante normalmente mantém o desempenho e a disponibilidade da aplicação e dos seus componentes. Componentes e recursos também estão localizados próximos uns dos outros. Esta abordagem torna a falha menos provável, mas falhas transitórias ainda podem ocorrer. Eventos inesperados como problemas externos de alimentação ou rede, ou outros cenários de desastre, podem causar falhas. Hardware redundante também pode ser dispendioso e muitas vezes subutilizado.

Os ambientes cloud podem proporcionar maior disponibilidade global porque distribuem cargas de trabalho por muitos servidores e utilizam redundância, failover automático e alocação dinâmica de recursos. Mas a natureza dos ambientes cloud torna as falhas transitórias mais prováveis por várias razões:

  • Muitos recursos num ambiente cloud são partilhados, e o acesso a esses recursos está sujeito a limitação para proteger esses recursos. Alguns serviços recusam ligações quando a carga atinge um determinado nível ou taxa máxima de throughput. Esta abordagem permite ao serviço processar pedidos existentes e manter o desempenho para todos os utilizadores. A limitação ajuda a manter a qualidade do serviço para vizinhos e outros inquilinos que utilizam o recurso partilhado.

  • Os ambientes de nuvem usam um grande número de unidades de hardware de mercadoria. Eles oferecem desempenho distribuindo dinamicamente a carga entre várias unidades de computação e componentes de infraestrutura. Eles oferecem confiabilidade ao reciclar automaticamente ou substituir unidades com falha. Devido a essa natureza dinâmica, falhas transitórias e falhas de conexão temporárias podem ocorrer ocasionalmente.

  • Existem frequentemente mais componentes de hardware, incluindo infraestruturas de rede como routers e balanceadores de carga, entre a aplicação e os recursos e serviços que utiliza. Esta infraestrutura pode, por vezes, introduzir latência de ligação extra e falhas de ligação transitórias.

  • As condições de rede entre o cliente e o servidor variam frequentemente, especialmente quando a comunicação atravessa a internet. Mesmo em locais locais, cargas de tráfego intenso podem atrasar a comunicação e causar falhas intermitentes na ligação.

Desafios

Falhas transitórias podem afetar significativamente a perceção da disponibilidade de uma aplicação, mesmo que a teste exaustivamente nas condições esperadas. Para garantir que as aplicações alojadas na cloud funcionam de forma fiável, devem enfrentar os seguintes desafios:

  • A aplicação deve ser capaz de detetar falhas quando ocorrem e determinar se são transitórias, de longa duração ou falhas terminais. Recursos diferentes normalmente retornam respostas distintas quando ocorre uma falha. Estas respostas também podem variar consoante o contexto da operação. Por exemplo, a resposta a um erro quando a aplicação lê a partir do armazenamento pode diferir da resposta a um erro ao escrever no armazenamento.

    Muitos recursos e serviços têm contratos de falha transitória bem documentados. Quando esta informação não está disponível, torna-se mais difícil determinar a natureza da falha e se é provável que seja transitória.

  • A aplicação tem de ser capaz de repetir a operação se determinar que a falha provavelmente será transitória. Também precisa de registar o número de vezes que tenta novamente a operação.

  • A aplicação deve usar uma estratégia de retentativa que se ajuste aos seus requisitos. A estratégia especifica quantas vezes a aplicação deve tentar novamente, o atraso entre tentativas e as ações a tomar após uma tentativa falhada. O número de tentativas e o atraso entre cada uma são frequentemente difíceis de determinar. A estratégia depende do tipo de recurso e das condições atuais de funcionamento do recurso e da aplicação.

Orientações gerais

As diretrizes a seguir podem ajudá-lo a estruturar mecanismos de processamento de falhas transitórias adequados para as suas aplicações.

Verifique se existe um mecanismo de retentativa incorporado

Muitos serviços fornecem um SDK ou biblioteca de cliente que contém um mecanismo transitório de tratamento de falhas. A política de retentativas que utiliza é normalmente adaptada à natureza e aos requisitos do serviço-alvo. Alternativamente, interfaces REST para serviços podem devolver informações que o ajudam a determinar se é necessária uma tentativa novamente e quanto tempo esperar até à próxima tentativa.

Use o mecanismo de tentativa de repetição incorporado quando uma opção interna estiver disponível, a menos que tenha requisitos específicos e bem compreendidos que tornem um comportamento de repetição diferente mais adequado ao seu cenário.

Os serviços Azure lidam com falhas transitórias de forma diferente. Alguns serviços fornecem políticas de repetição ao nível do SDK que incluem algoritmos de back-off configuráveis. Outros serviços fornecem funcionalidades de plataforma como verificações de integridade e tempos limite de visibilidade que complementam a lógica de retentativas ao nível da aplicação. Consulte o guia de fiabilidade de cada serviço Azure que utiliza. Estes guias incluem uma secção dedicada que fornece recomendações específicas para configuração de novas tentativas, ajustamento de tempos limite e monitorização da integridade do sistema.

Verifique se a repetição é adequada para a operação

Volte a tentar as tarefas apenas quando as falhas forem transitórias, como normalmente indicado pela natureza do erro, e quando a operação pode ter sucesso ao ser repetida. Para serviços baseados em HTTP, o código de resposta 429 (Demasiados Pedidos) e os erros de servidor 5xx são candidatos típicos para tentar novamente. A maioria dos erros 4xx do cliente, como 400, 401, 403 e 404, indica problemas que não se resolvem com uma nova tentativa. Não tente novamente operações que não tenham sucesso, como atualizar um item da base de dados que não existe ou chamar um serviço que devolveu um erro fatal.

De um modo geral, implementa retentativas apenas quando conseguires determinar o seu efeito total e quando compreenderes e conseguires validar as condições. Caso contrário, deixe o código de chamada realizar novas tentativas. Erros devolvidos de recursos e serviços fora do seu controlo podem evoluir ao longo do tempo, e pode ser que você precise rever a sua lógica de deteção de erros transitórios.

Ao criar serviços ou componentes, implemente códigos de erro e mensagens que ajudem os clientes a determinar se devem tentar novamente operações falhadas. Por exemplo, retorne um valor isTransient para indicar se o cliente deve tentar novamente a operação e sugira um atraso adequado antes da próxima tentativa. Se construir um serviço web, devolva erros personalizados que os seus contratos de serviço definem. Clientes genéricos podem não conseguir ler estes erros, mas são úteis quando crias clientes personalizados.

Determinar uma contagem de repetições e um intervalo adequados

Otimize a contagem de tentativas e o intervalo para o tipo de uso. Se não tentares repetir vezes suficientes, a aplicação não consegue completar a operação e falha. Se tentares demasiadas vezes ou não esperares tempo suficiente entre tentativas, a aplicação pode armazenar recursos como threads, ligações e memória durante longos períodos, o que afeta negativamente a saúde da aplicação. Para obter mais informações, consulte Padrão de Retentativa.

Adapte os valores para o intervalo de tempo e o número de tentativas de repetição ao tipo de operação. Por exemplo, se a operação fizer parte de uma interação do utilizador, o intervalo deve ser curto, devendo tentar apenas algumas vezes. Use esta abordagem para evitar fazer os utilizadores esperarem por uma resposta, o que mantém ligações abertas e pode reduzir a disponibilidade para outros utilizadores. Se a operação fizer parte de um fluxo de trabalho crítico ou de longa duração, onde cancelar e reiniciar o processo é dispendioso ou demorado, pode esperar mais tempo entre tentativas e tentar mais vezes.

Determinar os intervalos corretos entre tentativas é a parte mais difícil de desenhar uma estratégia bem-sucedida. As estratégias típicas utilizam os seguintes tipos de intervalo de repetição:

  • Recuo exponencial: A aplicação espera um curto período antes da primeira tentativa e depois aumenta exponencialmente o tempo entre cada tentativa subsequente. Por exemplo, pode tentar novamente a operação após dois segundos, quatro segundos, oito segundos e até um número definido de tentativas ou uma duração total. Adicione jitter, que é um pequeno atraso aleatório, a cada intervalo de tentativa para evitar que múltiplos clientes alinhem as suas tentativas e criem picos de carga no serviço alvo.

  • Intervalos incrementais: A aplicação espera um curto período antes da primeira tentativa e depois aumenta gradualmente o tempo entre cada tentativa subsequente. Por exemplo, pode tentar novamente a operação após 3 segundos, 7 segundos e 11 segundos.

  • Intervalos regulares: A aplicação aguarda o mesmo período de tempo entre cada tentativa. Por exemplo, pode tentar a operação novamente a cada três segundos.

  • Tentativa imediata: Falhas transitórias causadas por eventos como uma colisão de pacotes de rede ou um pico num componente de hardware são tipicamente breves. Nestes cenários, tentar novamente a operação imediatamente pode ajudar, pois pode ter sucesso se a falha for resolvida no tempo que a aplicação demora a montar e enviar o próximo pedido. Não tentes mais do que uma repetição imediata. Se a retentativa imediata falhar, mude para estratégias alternativas, como recuo exponencial ou ações de recuo.

  • Randomização: Qualquer uma das estratégias de retentativa listadas anteriormente pode incluir randomização para evitar que múltiplas instâncias do cliente façam tentativas de retentativa subsequentes ao mesmo tempo. Por exemplo, uma instância pode tentar novamente a operação após 3 segundos, 11 segundos ou 28 segundos, enquanto outra instância pode tentar novamente após 4 segundos, 12 segundos ou 26 segundos. A randomização é uma técnica útil que podes combinar com outras estratégias.

Utilize uma estratégia de recuo exponencial com jitter para operações em segundo plano, e utilize estratégias de retentativa em intervalos imediatos ou regulares para operações interativas. Em ambos os casos, escolha o atraso e a contagem de tentativas para que a latência máxima de todas as tentativas cumpra o requisito de latência de ponta a ponta.

Uma combinação de fatores contribui para o tempo máximo de espera total para uma operação retentada. Considere os seguintes fatores:

  • O tempo que uma ligação falhada demora a produzir uma resposta. Um valor de timeout no cliente normalmente determina a duração.

  • O atraso entre tentativas de repetição.

  • O número máximo de tentativas.

O total destes tempos pode resultar em tempos de operação longos, especialmente quando se utiliza uma estratégia de atraso exponencial, onde o intervalo entre tentativas aumenta rapidamente após cada falha. Se um processo tiver de cumprir um objetivo específico de nível de serviço (SLO), o tempo total de operação, incluindo todos os timeouts e atrasos, deve estar dentro dos limites definidos no SLO.

Tenha em conta o tempo limite das operações quando escolher intervalos de tentativa para evitar iniciar uma tentativa subsequente imediatamente, por exemplo, se o período de tempo limite for semelhante ao intervalo de tentativa. Determina se precisas de manter o período total possível, que é o tempo limite mais os intervalos de retentativa, abaixo de um limite de tempo total específico. Se uma operação tiver um tempo limite anormalmente curto ou longo, o tempo limite pode influenciar quanto tempo esperar e com que frequência repetir a operação.

Defina o tempo de espera para cada chamada de saída antes de implementar a lógica de tentativas de repetição. Os tempos limite, tentativas e estratégias de recuo funcionam em conjunto. Uma estratégia de tentativas repetidas só é tão eficaz quanto os tempos limite que regem cada tentativa individual. Tempos de expiração demasiado longos podem fazer com que threads e conexões se acumulem durante as interrupções. Tempos limite demasiado curtos causam falhas antecipadas em operações que, de outra forma, teriam sucesso.

Não implemente estratégias de reintento excessivamente agressivas. Estas estratégias usam intervalos demasiado curtos ou tentativas que ocorrem com demasiada frequência. Podem afetar negativamente o recurso ou serviço-alvo. Também podem impedir que o recurso ou serviço recupere, de modo que o recurso ou serviço continue a bloquear ou recusar pedidos. Este cenário cria um ciclo em que a aplicação envia mais pedidos ao recurso ou serviço, o que reduz ainda mais a sua capacidade de recuperação.

Use o tipo de exceção e quaisquer dados que contenha, ou os códigos de erro e mensagens que o serviço devolve, para otimizar o número de tentativas e o intervalo entre elas. Algumas exceções ou códigos de erro, como HTTP 503 (Serviço Indisponível), podem indicar que o serviço falhou e não responderá a novas tentativas. Quando uma resposta inclua um cabeçalho Retry-After, siga e espere pelo menos o tempo especificado antes da próxima tentativa. Este sinal fornecido pelo servidor reflete o cronograma de recuperação do serviço e tem prioridade sobre o cálculo de recuo do lado do cliente.

Use uma abordagem de fila de letra morta para que a informação do pedido recebido não se perca após todas as tentativas de repetição. Esta técnica adia o trabalho falhado para processamento posterior, em vez de o descartar.

Evite antipadrões

Na maioria dos casos, evite implementações que incluam camadas duplicadas de código de repetição. Evite conceções que utilizem mecanismos de repetição em cascata ou que apliquem repetição em todas as etapas de uma operação que envolva uma hierarquia de pedidos, a menos que tenha requisitos específicos. Nestes casos excecionais, utilize políticas que limitem o número de tentativas e períodos de atraso, e certifique-se de que compreende as consequências.

Por exemplo, considere um componente que faz um pedido a outro, que depois acede ao serviço alvo. Uma repetição com um número de três em ambas as chamadas soma um total de nove tentativas ao serviço.

Muitos serviços e recursos implementam um mecanismo de repetição incorporado. Desligue ou modifique estes mecanismos se precisar implementar tentativas repetidas a um nível superior. Para mais informações sobre os riscos de tentativas descoordenadas, consulte antipadrão Retry Storm.

Nunca implemente um mecanismo de repetição interminável. Esta abordagem normalmente impede que o recurso ou serviço recupere de situações de sobrecarga e faz com que a limitação e a recusa de ligações continuem por mais tempo. Use um número finito de tentativas ou implemente um padrão como Circuit Breaker para permitir que o serviço se recupere.

Implemente um orçamento de tentativas para limitar o número total de tentativas em todas as requisições dentro de um processo ou serviço, além dos limites para cada requisição individual. Por exemplo, pode permitir que um processo faça no máximo 60 tentativas por minuto contra uma dependência específica. Se esgotar o orçamento, reprove imediatamente o pedido em vez de tentar novamente.

Os limites de tentativas por pedido, por si só, não impedem um cenário em que muitos pedidos simultâneos, cada um retentando algumas vezes, juntos sobrecarreguem um serviço subsequente que já está com dificuldades. Um orçamento de retries limita a carga agregada de retries e pode fazer a diferença entre um problema de capacidade localizada e uma falha em cascata.

Nunca faça uma tentativa imediata mais do que uma vez.

Evite usar um intervalo de repetição regular ao acessar serviços e recursos no Azure, especialmente quando tiver um alto número de tentativas de repetição. A melhor abordagem neste cenário é uma estratégia de recuo exponencial que utilize uma capacidade de quebra de circuito.

Impeça que várias instâncias do mesmo cliente, ou várias instâncias de clientes diferentes, enviem novas tentativas simultaneamente. Se este cenário for provável, introduza a randomização nos intervalos de nova tentativa.

Teste a sua estratégia de repetição e a sua implementação

Teste a sua estratégia de tentativa de nova tentativa numa vasta gama de condições, especialmente quando a aplicação e os seus recursos ou serviços-alvo operam sob condições de carga extrema. Para verificar o comportamento durante os testes, pode tomar as seguintes ações:

  • Inclua falhas transitórias em suas práticas de engenharia de caos e injeção de falhas , introduzindo-as propositalmente em seus ambientes de não produção e produção. Por exemplo, enviar pedidos não suportados ou adicionar código que deteta pedidos de teste e responde com diferentes tipos de erros.

  • Crie uma versão simulada do recurso ou serviço que devolve uma série de erros que o serviço real pode devolver. Certifique-se de que cobre todos os tipos de erro que a sua estratégia de nova tentativa deteta.

  • Para serviços personalizados que cria e implementa, force a ocorrência de erros transitórios ao desligar temporariamente o serviço ou sobrecarregá-lo. Não tente sobrecarregar recursos ou serviços partilhados no Azure.

  • Considera usar um serviço de injeção de falhas para executar experiências controladas contra os teus recursos Azure. Por exemplo, o Azure Chaos Studio suporta falhas diretas ao serviço, como adicionar latência de rede ou reiniciar um cluster de cache, e falhas baseadas em agentes, como aplicar pressão de memória ou terminar um processo numa máquina virtual (VM). Pode integrar experiências de injeção de falhas nos seus pipelines de integração contínua e entrega contínua (CI/CD) para validar continuamente a resiliência como parte do seu processo de implementação.

  • Para APIs baseadas em HTTP, considere usar uma biblioteca nos seus testes automatizados para alterar o resultado dos pedidos HTTP, seja adicionando tempos extra de ida e volta ou alterando a resposta, como o código de estado HTTP, cabeçalhos, corpo ou outros fatores. Esta abordagem ajuda-o a testar deterministicamente um subconjunto das condições de falha para falhas transitórias e outros tipos de falhas.

  • Execute testes de alto fator de carga e concorrentes para garantir que o mecanismo e a estratégia de retentativa funcionam corretamente nestas condições. Estes testes também ajudam a confirmar que as tentativas de novas não afetam as operações do cliente nem causam contaminação cruzada entre requisições.

Gerir definições de política de repetição

Uma política de repetição é uma combinação de todos os elementos da sua estratégia de repetição. Define o mecanismo de deteção que determina os seguintes fatores:

  • Se uma falha é provavelmente transitória
  • O tipo de intervalo a usar, como recuo regular, exponencial ou randomização
  • Os valores reais dos intervalos
  • O número de tentativas

Implementar tentativas novamente em muitos locais, incluindo em aplicações básicas e em cada camada de aplicações mais complexas. Em vez de codificar diretamente elementos de políticas em múltiplos locais, use um ponto central para armazenar todas as políticas. Por exemplo, armazene valores como o intervalo e a contagem de repetições em arquivos de configuração do aplicativo, leia-os em tempo de execução e crie programaticamente as políticas de repetição. Esta abordagem simplifica a gestão das definições e a modificação e ajuste fino dos valores para responder a requisitos e cenários em mudança. Projete o sistema para armazenar os valores em vez de reler um ficheiro de configuração para cada pedido, e use valores por defeito, caso a configuração não forneça esses valores.

Armazene os valores usados para construir as políticas de retentativa em tempo de execução no sistema de configuração da aplicação para que possa alterá-los sem precisar de reiniciar a aplicação.

Aproveite as estratégias de reintento integradas ou padrão disponíveis nas APIs do cliente que utiliza, mas apenas quando forem adequadas ao seu cenário. Estas estratégias são tipicamente genéricas. Podem ser adequados em alguns cenários, mas noutros não oferecem toda a gama de opções para satisfazer as tuas necessidades específicas. Para determinar os valores mais adequados, teste para compreender como as definições afetam a sua aplicação. Para predefinições de tentativas de repetição específicas de serviço e opções de configuração, consulte o guia de fiabilidade de cada serviço da Azure na(s) sua(s) arquitetura(s).

Registar e monitorizar falhas transitórias e não transitórias

A sua estratégia de tentativas de nova tentativa deve incluir o tratamento de exceções e a instrumentação que regista as tentativas de nova tentativa. Uma falha e uma repetição transitórias ocasionais são esperadas e não indicam um problema. Mas um número regular ou crescente de tentativas geralmente indica um problema que pode causar uma falha ou reduzir o desempenho e a disponibilidade da aplicação.

Registe falhas transitórias como entradas de aviso, em vez de entradas de erro, para que os sistemas de monitorização não as detetem como erros de aplicação que podem acionar falsos alertas.

Armazene um valor nos seus registos que indique se a limitação no serviço ou outros tipos de falhas, como falhas de ligação, provocam tentativas de repetição. Esta abordagem ajuda-o a diferenciar as causas durante a análise de dados. Um aumento dos erros de limitação geralmente indica uma falha de conceção na aplicação ou a necessidade de migrar para um serviço premium que forneça hardware dedicado.

Meça e registre o tempo total decorrido para operações que incluam um mecanismo de repetição. Esta métrica indica com precisão o efeito global que as falhas transitórias têm nos tempos de resposta do utilizador, na latência do processo e na eficiência dos casos de uso da aplicação. Registe o número de tentativas que ocorrem para perceberes os fatores que contribuem para o tempo de resposta.

Implemente um sistema de telemetria e monitorização que emita alertas quando as seguintes métricas aumentam:

  • O número e a taxa de falhas
  • O número médio de tentativas
  • O tempo total que decorre até que as operações tenham sucesso

Gerir operações que falham continuamente

Crie um plano para lidar com operações que continuam a falhar a cada tentativa. Estas situações são inevitáveis.

  • Uma estratégia de tentativa define o número máximo de vezes que uma aplicação deve voltar a tentar uma operação. Não impede a aplicação de repetir a operação para começar com o mesmo número de tentativas. Por exemplo, se um serviço de processamento de encomendas falhar com um erro fatal que o remove permanentemente do serviço, a estratégia de reintento pode detetar um timeout de ligação e considerá-lo como uma falha transitória. O código tenta novamente a operação o número de vezes especificado e depois para. Quando outro cliente faz uma encomenda, a aplicação tenta realizar a operação novamente, faz várias tentativas e falha.

  • Para evitar tentativas contínuas em operações que falham continuamente, implemente o padrão Circuit Breaker. Quando utiliza este padrão, se o número de falhas dentro de uma janela de tempo especificada ultrapassar um limiar, os pedidos regressam imediatamente ao chamador como erros, e a aplicação não tenta aceder ao recurso ou serviço falhado.

  • A aplicação pode testar periodicamente o serviço, de forma intermitente e com longos intervalos entre os pedidos, para detetar quando este fica disponível. O intervalo depende de fatores como a criticidade da operação e a natureza do serviço. Pode variar de alguns minutos a várias horas. Quando o teste for bem-sucedido, a aplicação poderá retomar as operações normais e passar pedidos para o serviço recentemente recuperado.

  • Entretanto, pode recorrer a outra instância do serviço num datacenter ou aplicação diferentes. Pode também usar um serviço semelhante que ofereça funcionalidades compatíveis, mas mais simples, ou fazer algumas operações alternativas com base na esperança de que o serviço esteja disponível em breve. Por exemplo, pode armazenar pedidos para o serviço numa fila ou base de dados e processá-los novamente mais tarde. Ou pode ser possível redirecionar o utilizador para uma instância alternativa da aplicação, degradar o desempenho da aplicação mas ainda assim fornecer funcionalidades aceitáveis, ou simplesmente devolver uma mensagem ao utilizador a indicar que a aplicação não está disponível no momento.

Outras considerações

Ao determinar os valores do número de tentativas e dos intervalos de nova tentativa de uma política, considere se a operação sobre o serviço ou recurso faz parte de uma operação de longa duração ou de múltiplas etapas. Pode ser difícil ou dispendioso compensar todos os passos operacionais que já foram bem-sucedidos quando um deles falha. Neste caso, um longo intervalo e um grande número de tentativas podem ser aceitáveis, desde que a estratégia não bloqueie outras operações ao manter ou bloquear recursos escassos.

Considere se tentar novamente a mesma operação pode causar inconsistências nos dados. Se uma aplicação repetir partes de um processo em vários passos e as operações não forem idempotentes, podem ocorrer inconsistências. Por exemplo, se uma operação que incrementa um valor se repete, produz um resultado incorreto. Uma operação repetida que envia uma mensagem para uma fila também pode causar problemas a um consumidor que não consegue detetar mensagens duplicadas. Para evitar esses cenários, projete cada etapa como uma operação idempotente. Para mais informações, veja Padrão do Consumidor Idempotente.

Seja intencional quanto ao âmbito das operações que a aplicação aborda. Por exemplo, pode ser mais fácil implementar lógica de tentativa repetida a um nível que inclua várias operações e repeti-las todas se uma falhar. Mas esta abordagem pode levar a problemas de idempotência ou a operações de reversão desnecessárias.

Se escolher um âmbito de retentativa que inclua várias operações, tenha em conta a latência total de todas elas ao determinar os intervalos de retentativa, ao monitorizar o tempo decorrido da operação e antes de levantar alertas para falhas.

Considere como a sua estratégia de repetição pode afetar os vizinhos e outros inquilinos numa aplicação partilhada ao utilizar recursos e serviços partilhados. Políticas agressivas de nova tentativa podem aumentar o número de falhas transitórias que ocorrem para outros utilizadores e para aplicações que partilham os recursos e serviços. As políticas de retentativa que outros utilizadores implementam também podem afetar a sua aplicação. Para aplicações críticas para o negócio, utilize serviços premium que não sejam partilhados. Esta abordagem permite-lhe controlar a carga e a consequente limitação de recursos e serviços, o que pode justificar o custo adicional.

Próximo passo