Tentativas novamente no AWS SDK para Kotlin - AWS SDK para Kotlin

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á.

Tentativas novamente no AWS SDK para Kotlin

Ligações para retornar Serviços da AWS ocasionalmente exceções inesperadas. Certos tipos de erros, como erros transitórios ou de limitação, podem ser bem-sucedidos se a chamada for repetida.

Esta página descreve como ele AWS SDK para Kotlin lida com novas tentativas automaticamente e como personalizar o comportamento de repetição para seus aplicativos.

Entendendo o comportamento de repetição

As seções a seguir explicam como o SDK determina quando repetir as solicitações e quais exceções são consideradas passíveis de nova tentativa.

Configuração de nova tentativa padrão

Por padrão, cada cliente de serviço é configurado automaticamente com uma estratégia de repetição padrão. A configuração padrão tenta uma chamada que falha até três vezes (a tentativa inicial mais duas tentativas). O atraso intermediário entre cada chamada é configurado com recuo exponencial e instabilidade aleatória para evitar tempestades de novas tentativas. Essa configuração funciona para a maioria dos casos de uso, mas pode ser inadequada em algumas circunstâncias, como sistemas de alto rendimento.

O SDK tenta novas tentativas somente em caso de erros que possam ser repetidos. Exemplos de erros que podem ser repetidos são tempos limite de soquete, limitação do lado do serviço, falhas de simultaneidade ou bloqueio otimistas e erros transitórios de serviço. Parâmetros ausentes ou inválidos, authentication/security erros e exceções de configuração incorreta não são considerados passíveis de nova tentativa.

Você pode personalizar a estratégia de repetição padrão definindo o máximo de tentativas, atrasos e recuos e a configuração do token bucket.

Quais exceções podem ser repetidas?

O AWS SDK para Kotlin usa uma política de repetição pré-configurada que determina quais exceções podem ser repetidas. A configuração do cliente de serviço tem uma retryPolicy propriedade que especifica a política aplicada às novas tentativas. Se nenhum valor personalizado for especificado, o valor padrão será AwsRetryPolicy.

As seguintes exceções foram determinadas como passíveis de nova tentativa por: AwsRetryPolicy

Tentável novamente por código de erro

Qualquer um ServiceException com um sdkErrorMetadata.errorCode dos seguintes:

  • BandwidthLimitExceeded

  • EC2ThrottledException

  • IDPCommunicationError

  • LimitExceededException

  • PriorRequestNotComplete

  • ProvisionedThroughputExceededException

  • RequestLimitExceeded

  • RequestThrottled

  • RequestThrottledException

  • RequestTimeout

  • RequestTimeoutException

  • SlowDown

  • ThrottledException

  • Throttling

  • ThrottlingException

  • TooManyRequestsException

  • TransactionInProgressException

Tentável novamente pelo código de status HTTP

Qualquer um ServiceException com um sdkErrorMetadata.statusCode dos seguintes:

  • 500 (Erro de serviço interno)

  • 502 (Gateway inválido)

  • 503 (Serviço indisponível)

  • 504 (Tempo limite do gateway)

Tentável novamente por tipo de erro

Qualquer um ServiceException com um sdkErrorMetadata.errorType dos seguintes:

  • ErrorType.Server(como erros internos de serviço)

  • ErrorType.Client(como uma solicitação inválida, um recurso não encontrado, acesso negado etc.)

Tentável novamente por metadados do SDK

Em qualquer SdkBaseException lugar:

  • sdkErrorMetadata.isRetryableé true (como um tempo limite do lado do cliente, networking/socket erro, etc.)

  • sdkErrorMetadata.isThrottlingé true (como fazer muitas solicitações em um curto espaço de tempo)

Para obter uma lista completa das exceções que podem ser lançadas por cada cliente de serviço, consulte a documentação de referência da API específica do serviço.

Verifique se uma exceção pode ser repetida

Para determinar se o SDK considera uma exceção passível de repetição, verifique a isRetryable propriedade das exceções detectadas:

try { dynamoDbClient.putItem { tableName = "MyTable" item = mapOf("id" to AttributeValue.S("123")) } } catch (e: SdkBaseException) { println("Exception occurred: ${e.message}") if (e.sdkErrorMetadata.isRetryable) { println("This exception is retryable - SDK will automatically retry") println("If you're seeing this, retries may have been exhausted") } else { println("This exception is not retryable - fix the underlying issue") // Common non-retryable scenarios. when { e.message?.contains("ValidationException") == true -> println("Check your request parameters") e.message?.contains("AccessDenied") == true -> println("Check your IAM permissions") e.message?.contains("ResourceNotFound") == true -> println("Verify the resource exists") } } }

Quais exceções chegam ao seu código quando as novas tentativas falham

Quando o mecanismo de repetição do SDK não consegue resolver um problema, exceções são lançadas no código do aplicativo. Compreender esses tipos de exceção ajuda você a implementar o tratamento adequado de erros. Essas não são as exceções que acionam as tentativas. Elas são tratadas internamente pelo SDK.

Seu código detectará os seguintes tipos de exceções quando as novas tentativas forem esgotadas ou desativadas:

Exceções de serviço após nova tentativa de exaustão

Quando todas as tentativas de repetição falham, seu código captura a exceção de serviço final (subclasse deAwsServiceException) que causou a falha na última tentativa de repetição. Isso pode ser um erro de limitação, erro do servidor ou outra exceção específica do serviço que o SDK não conseguiu resolver por meio de novas tentativas.

Exceções de rede após a exaustão de novas tentativas

Quando os problemas de rede persistem em todas as tentativas, seu código detecta ClientException instâncias com problemas como tempos limite de conexão, falhas na resolução de DNS e outros problemas de conectividade que o SDK não conseguiu resolver.

Use o padrão a seguir para lidar com essas exceções em seu aplicativo:

try { s3Client.getObject { bucket = "amzn-s3-demo-bucket" key = "my-key" } } catch (e: AwsServiceException) { // Service-side errors that persisted through all retries. println("Service error after retries: ${e.errorDetails?.errorCode} - ${e.message}") // Handle specific service errors that couldn't be resolved. if (e.errorDetails?.errorCode == "ServiceQuotaExceededException" || e.errorDetails?.errorCode == "ThrottlingException") { println("Rate limiting persisted - consider longer delays or quota increase") } } catch (e: ClientException) { // Client-side errors (persistent network issues, DNS resolution failures, etc.) println("Client error after retries: ${e.message}") }

Personalizando o comportamento de repetição

As seções a seguir mostram como personalizar o comportamento de repetição do SDK para seu caso de uso específico.

Configurar o máximo de tentativas

Você pode personalizar o máximo padrão de tentativas (3) no bloco retryStrategy DSL durante a construção do cliente.

val dynamoDb = DynamoDbClient.fromEnvironment { retryStrategy { maxAttempts = 5 } }

Com o cliente de serviço do DynamoDB mostrado no snippet anterior, o SDK tenta chamadas de API que falham até cinco vezes (a tentativa inicial mais quatro tentativas).

Você pode desativar completamente as novas tentativas automáticas definindo o máximo de tentativas como uma, conforme mostrado no trecho a seguir.

val dynamoDb = DynamoDbClient.fromEnvironment { retryStrategy { maxAttempts = 1 // The SDK makes no retries. } }

Configure atrasos e recuos

Se uma nova tentativa for necessária, a estratégia de repetição padrão aguarda antes de fazer a tentativa subsequente. O atraso na primeira tentativa é pequeno, mas cresce exponencialmente nas tentativas posteriores. A quantidade máxima de atraso é limitada para que não cresça muito.

Finalmente, a instabilidade aleatória é aplicada aos atrasos entre todas as tentativas. A instabilidade ajuda a mitigar o efeito de grandes frotas que podem causar novas tempestades. (Veja esta postagem no blog de AWS arquitetura para uma discussão mais profunda sobre recuo exponencial e instabilidade.)

Os parâmetros de atraso são configuráveis no bloco delayProviderDSL.

val dynamoDb = DynamoDbClient.fromEnvironment { retryStrategy { delayProvider { initialDelay = 100.milliseconds maxBackoff = 5.seconds } } }

Com a configuração mostrada no trecho anterior, o cliente atrasa a primeira tentativa em até 100 milissegundos. O tempo máximo entre qualquer tentativa de repetição é de 5 segundos.

Os parâmetros a seguir estão disponíveis para atrasos de ajuste e recuo.

Parameter Valor padrão Descrição
initialDelay 10 milissegundos A quantidade máxima de atraso para a primeira tentativa. Quando a instabilidade é aplicada, a quantidade real de atraso pode ser menor.
jitter 1.0 (instabilidade total)

A amplitude máxima pela qual reduzir aleatoriamente o atraso calculado. O valor padrão de 1,0 significa que o atraso calculado pode ser reduzido para qualquer valor de até 100% (por exemplo, até 0). Um valor de 0,5 significa que o atraso calculado pode ser reduzido em até metade. Assim, um atraso máximo de 10 ms pode ser reduzido para algo entre 5 ms e 10 ms. Um valor de 0,0 significa que nenhuma instabilidade é aplicada.

Importante

️ A configuração do Jitter é um recurso avançado. A personalização desse comportamento normalmente não é recomendada.

maxBackoff 20 segundos A quantidade máxima de atraso a ser aplicada a qualquer tentativa. Definir esse valor limita o crescimento exponencial que ocorre entre as tentativas subsequentes e evita que o máximo calculado seja muito grande. Esse parâmetro limita o atraso calculado antes que a instabilidade seja aplicada. Se aplicada, a instabilidade pode reduzir ainda mais o atraso.
scaleFactor 1.5

A base exponencial pela qual os atrasos máximos subsequentes serão aumentados. Por exemplo, considerando um initialDelay de 10 ms e um scaleFactor de 1,5, os seguintes atrasos máximos seriam calculados:

  • Tentativa 1 novamente: 10ms × 1,5⁰ = 10ms

  • Tentativa 2 novamente: 10ms × 1,5¹ = 15ms

  • Tentativa 3 novamente: 10ms × 1,5² = 22,5 ms

  • Tentativa 4 novamente: 10 ms × 1,5³ = 33,75 ms

Quando a instabilidade é aplicada, a quantidade real de cada atraso pode ser menor.

Configurar o repositório de tokens de nova tentativa

Você pode modificar ainda mais o comportamento da estratégia de repetição padrão ajustando a configuração padrão do token bucket. O repositório de tokens de repetição ajuda a reduzir as novas tentativas com menor probabilidade de sucesso ou que podem levar mais tempo para serem resolvidas, como falhas de tempo limite e limitação.

Importante

A configuração do token bucket é um recurso avançado. A personalização desse comportamento normalmente não é recomendada.

Cada tentativa de nova tentativa (opcionalmente incluindo a tentativa inicial) diminui parte da capacidade do token bucket. O valor diminuído depende do tipo de tentativa. Por exemplo, tentar novamente erros transitórios pode ser barato, mas tentar novamente erros de tempo limite ou de limitação pode ser mais caro.

Uma tentativa bem-sucedida retorna a capacidade para o bucket. O balde não pode ser incrementado além de sua capacidade máxima nem diminuído abaixo de zero.

Dependendo do valor da useCircuitBreakerMode configuração, as tentativas de diminuir a capacidade abaixo de zero resultam em um dos seguintes resultados:

  • Se a configuração for TRUE, uma exceção será lançada — por exemplo, se muitas tentativas tiverem ocorrido e for improvável que mais tentativas sejam bem-sucedidas.

  • Se a configuração for FALSA, haverá um atraso — por exemplo, atrasos até que o bucket tenha capacidade suficiente novamente.

nota

Quando o disjuntor é ativado (o token bucket atinge a capacidade zero), o SDK emite um ClientException com a mensagem “Capacidade de repetição excedida”. Essa é uma exceção do lado do cliente, não umaAwsServiceException, porque se origina da lógica de repetição do SDK e não do serviço. AWS A exceção é lançada imediatamente sem tentar a operação, ajudando a evitar novas tentativas durante interrupções no serviço.

Os parâmetros do token bucket são configuráveis no bloco tokenBucketDSL:

val dynamoDb = DynamoDbClient.fromEnvironment { retryStrategy { tokenBucket { maxCapacity = 100 refillUnitsPerSecond = 2 } } }

Os parâmetros a seguir estão disponíveis para ajustar o repositório de tokens de repetição:

Parameter Valor padrão Descrição
initialTryCost 0 O valor a ser diminuído do intervalo nas tentativas iniciais. O valor padrão de 0 significa que nenhuma capacidade será diminuída e, portanto, as tentativas iniciais não serão interrompidas ou atrasadas.
initialTrySuccessIncrement 1 O valor para incrementar a capacidade quando a tentativa inicial foi bem-sucedida.
maxCapacity 500 A capacidade máxima do token bucket. O número de tokens disponíveis não pode exceder esse número.
refillUnitsPerSecond 0 A quantidade de capacidade adicionada novamente ao balde a cada segundo. Um valor de 0 significa que nenhuma capacidade é adicionada novamente automaticamente. (Por exemplo, somente tentativas bem-sucedidas resultam no aumento da capacidade). Um valor de 0 useCircuitBreakerMode precisa ser VERDADEIRO.
retryCost 5 A quantidade a ser diminuída do compartimento em caso de uma tentativa após uma falha transitória. A mesma quantidade é reincrementada de volta para o bucket se a tentativa for bem-sucedida.
timeoutRetryCost 10 O valor a ser diminuído do bucket por uma tentativa após uma falha de tempo limite ou limitação. A mesma quantidade é reincrementada de volta para o bucket se a tentativa for bem-sucedida.
useCircuitBreakerMode VERDADEIRO Determina o comportamento quando uma tentativa de diminuir a capacidade faria com que a capacidade do bucket caísse abaixo de zero. Quando TRUE, o token bucket lançará uma exceção indicando que não existe mais capacidade de repetição. Quando FALSO, o token bucket atrasará a tentativa até que a capacidade suficiente seja reabastecida.

Para obter informações detalhadas sobre os tipos de exceção lançados durante cenários de repetição, incluindo exceções de disjuntores, consulte. Quais exceções chegam ao seu código quando as novas tentativas falham

Configurar novas tentativas adaptáveis

Como alternativa à estratégia de repetição padrão, a estratégia de repetição adaptativa é uma abordagem avançada que busca a taxa de solicitação ideal para minimizar os erros de limitação.

Importante

As novas tentativas adaptáveis são um modo de repetição avançado. Normalmente, não é recomendável usar essa estratégia de repetição.

As novas tentativas adaptáveis incluem todos os recursos das novas tentativas padrão. Ele adiciona um limitador de taxa do lado do cliente que mede a taxa de solicitações limitadas em comparação com solicitações não limitadas. Também limita o tráfego para tentar permanecer dentro de uma largura de banda segura, o que, idealmente, causa zero erros de limitação.

A taxa se adapta em tempo real às mudanças nas condições de serviço e nos padrões de tráfego e pode aumentar ou diminuir a taxa de tráfego de acordo. Fundamentalmente, o limitador de taxa pode atrasar as tentativas iniciais em cenários de tráfego intenso.

Você seleciona a estratégia de repetição adaptativa fornecendo um parâmetro adicional ao retryStrategy método. Os parâmetros do limitador de taxa são configuráveis no bloco rateLimiterDSL.

val dynamoDb = DynamoDbClient.fromEnvironment { retryStrategy(AdaptiveRetryStrategy) { maxAttempts = 10 rateLimiter { minFillRate = 1.0 smoothing = 0.75 } } }
nota

A estratégia de repetição adaptativa pressupõe que o cliente trabalhe com um único recurso (por exemplo, uma tabela do DynamoDB ou um bucket do Amazon S3).

Se você usa um único cliente para vários recursos, a limitação ou as interrupções associadas a um recurso resultam em maior latência e falhas quando o cliente acessa todos os outros recursos. Ao usar a estratégia de repetição adaptável, recomendamos que você use um único cliente para cada recurso.