Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changelog/feature-retry-behavior-2-1-default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "feature",
"category": "aws-cpp-sdk-core",
"contributor": "pulimsr",
"description": "Make Retry Behavior 2.1 the default retry behavior and remove AWS_NEW_RETRIES_2026. Set AWS_RETRY_MODE=legacy or retry_mode = legacy to keep the previous DefaultRetryStrategy behavior."
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,18 @@ DynamoDBClientConfiguration::DynamoDBClientConfiguration(const Aws::Client::Clie
DynamoDBClientConfiguration::DynamoDBClientConfiguration(const char* inputProfileName, bool shouldDisableIMDS)
: BaseClientConfigClass(inputProfileName, shouldDisableIMDS), enableEndpointDiscovery(ClientConfiguration::enableEndpointDiscovery) {
LoadDynamoDBSpecificConfig(Aws::String(inputProfileName));
if (this->retryStrategy) {
this->retryStrategy = this->configFactories.retryStrategyCreateFn();
}
}

DynamoDBClientConfiguration::DynamoDBClientConfiguration(bool useSmartDefaults, const char* defaultMode, bool shouldDisableIMDS)
: BaseClientConfigClass(useSmartDefaults, defaultMode, shouldDisableIMDS),
enableEndpointDiscovery(ClientConfiguration::enableEndpointDiscovery) {
LoadDynamoDBSpecificConfig(this->profileName);
if (this->retryStrategy) {
this->retryStrategy = this->configFactories.retryStrategyCreateFn();
}
}

DynamoDBClientConfiguration::DynamoDBClientConfiguration(const Aws::Client::ClientConfiguration& config)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,18 @@ DynamoDBStreamsClientConfiguration::DynamoDBStreamsClientConfiguration(const Aws
DynamoDBStreamsClientConfiguration::DynamoDBStreamsClientConfiguration(const char* inputProfileName, bool shouldDisableIMDS)
: BaseClientConfigClass(inputProfileName, shouldDisableIMDS) {
LoadDynamoDBStreamsSpecificConfig(Aws::String(inputProfileName));
if (this->retryStrategy) {
this->retryStrategy = this->configFactories.retryStrategyCreateFn();
}
}

DynamoDBStreamsClientConfiguration::DynamoDBStreamsClientConfiguration(bool useSmartDefaults, const char* defaultMode,
bool shouldDisableIMDS)
: BaseClientConfigClass(useSmartDefaults, defaultMode, shouldDisableIMDS) {
LoadDynamoDBStreamsSpecificConfig(this->profileName);
if (this->retryStrategy) {
this->retryStrategy = this->configFactories.retryStrategyCreateFn();
}
}

DynamoDBStreamsClientConfiguration::DynamoDBStreamsClientConfiguration(const Aws::Client::ClientConfiguration& config)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ namespace Aws

error.SetResponseHeaders(httpResponse->GetHeaders());
error.SetResponseCode(httpResponse->GetResponseCode());
if (error.GetResponseCode() == Aws::Http::HttpResponseCode::TOO_MANY_REQUESTS && error.GetErrorType() == CoreErrors::UNKNOWN)
{
error.SetRetryableType(RetryableType::RETRYABLE_THROTTLING);
}
error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost());
AWS_LOGSTREAM_ERROR(GetClientLogTag(), error);
return error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class AWS_CORE_API AdaptiveRetryStrategy : public StandardRetryStrategy
*/
AdaptiveRetryStrategy(long maxAttempts = 3);
AdaptiveRetryStrategy(std::shared_ptr<RetryQuotaContainer> retryQuotaContainer, long maxAttempts = 3);
AdaptiveRetryStrategy(long maxAttempts, double transientBackoffBaseSec);

/**
* Retrieve and consume a send token.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ namespace Aws
struct ProviderFactories
{
/**
* Retry Strategy factory method. Default is DefaultRetryStrategy (i.e. exponential backoff).
* Retry Strategy factory method. Default is StandardRetryStrategy.
*/
std::function<std::shared_ptr<RetryStrategy>()> retryStrategyCreateFn;
/**
Expand Down Expand Up @@ -229,7 +229,7 @@ namespace Aws
*/
unsigned long lowSpeedLimit = 1;
/**
* Strategy to use in case of failed requests. Default is DefaultRetryStrategy (i.e. exponential backoff).
* Strategy to use in case of failed requests. Default is StandardRetryStrategy.
* Provide retry strategy here or via a factory method.
*/
std::shared_ptr<RetryStrategy> retryStrategy = nullptr;
Expand Down Expand Up @@ -652,7 +652,7 @@ namespace Aws

/**
* A helper function to initialize a retry strategy.
* Default is DefaultRetryStrategy (i.e. exponential backoff)
* Default is StandardRetryStrategy. Retry mode "legacy" uses DefaultRetryStrategy.
*/
AWS_CORE_API std::shared_ptr<RetryStrategy> InitRetryStrategy(Aws::String retryMode = "");
AWS_CORE_API std::shared_ptr<RetryStrategy> InitRetryStrategy(int maxRetries, Aws::String retryMode = "");
Expand Down
21 changes: 21 additions & 0 deletions src/aws-cpp-sdk-core/include/aws/core/internal/RetryStrategyImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
#include <aws/core/client/AWSError.h>
#include <aws/core/client/CoreErrors.h>
#include <aws/core/client/RetryStrategy.h>
#include <aws/core/utils/memory/stl/AWSString.h>
#include <aws/core/utils/threading/ReaderWriterLock.h>

#include <memory>

namespace Aws
{
namespace Client
Expand Down Expand Up @@ -73,5 +76,23 @@ namespace Aws
mutable Aws::Utils::Threading::ReaderWriterLock m_retryQuotaLock;
int m_retryQuota;
};

namespace Internal
{
AWS_CORE_LOCAL std::shared_ptr<RetryStrategy> CreateLegacyRetryStrategy();

AWS_CORE_LOCAL bool UsesRetryBehavior21(const RetryStrategy* retryStrategy);

AWS_CORE_LOCAL std::shared_ptr<RetryStrategy> InitRetryStrategyForDefaultsMode(const Aws::String& defaultsModeRetryMode);

inline void ClassifyUnmodeledTooManyRequests(AWSError<CoreErrors>& error)
{
if (error.GetResponseCode() == Aws::Http::HttpResponseCode::TOO_MANY_REQUESTS &&
error.GetErrorType() == CoreErrors::UNKNOWN)
{
error.SetRetryableType(RetryableType::RETRYABLE_THROTTLING);
}
}
} // namespace Internal
} // namespace Client
} // namespace Aws
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,7 @@ namespace client
Aws::MakeShared<features::ChunkingInterceptor>("AwsSmithyClientBase",
m_httpClient->IsDefaultAwsHttpClient() ? Aws::Client::HttpClientChunkedMode::DEFAULT : m_clientConfig->httpClientChunkedMode,
m_clientConfig->awsChunkedBufferSize)
}),
m_enableNewRetries{Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_NEW_RETRIES_2026").c_str()) == "true"}
})
{

baseInit();
Expand Down
5 changes: 3 additions & 2 deletions src/aws-cpp-sdk-core/source/client/AWSClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/client/CoreErrors.h>
#include <aws/core/client/RetryStrategy.h>
#include <aws/core/internal/RetryStrategyImpl.h>
#include <aws/core/client/RequestCompression.h>
#include <aws/core/http/HttpClient.h>
#include <aws/core/http/HttpClientFactory.h>
Expand Down Expand Up @@ -177,7 +178,7 @@ AWSClient::AWSClient(const Aws::Client::ClientConfiguration& configuration,
m_httpClient->IsDefaultAwsHttpClient() ? Aws::Client::HttpClientChunkedMode::DEFAULT : configuration.httpClientChunkedMode,
configuration.awsChunkedBufferSize),
m_userAgentInterceptor},
m_enableNewRetries{Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_NEW_RETRIES_2026").c_str()) == "true"},
m_enableNewRetries{Aws::Client::Internal::UsesRetryBehavior21(m_retryStrategy.get())},
m_disableExpectHeader(configuration.disableExpectHeader)
{
}
Expand Down Expand Up @@ -209,7 +210,7 @@ AWSClient::AWSClient(const Aws::Client::ClientConfiguration& configuration,
m_httpClient->IsDefaultAwsHttpClient() ? Aws::Client::HttpClientChunkedMode::DEFAULT : configuration.httpClientChunkedMode,
configuration.awsChunkedBufferSize),
m_userAgentInterceptor},
m_enableNewRetries{Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_NEW_RETRIES_2026").c_str()) == "true"},
m_enableNewRetries{Aws::Client::Internal::UsesRetryBehavior21(m_retryStrategy.get())},
m_disableExpectHeader(configuration.disableExpectHeader)
{
}
Expand Down
4 changes: 4 additions & 0 deletions src/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <aws/core/client/AWSError.h>
#include <aws/core/client/CoreErrors.h>
#include <aws/core/utils/cbor/CborValue.h>
#include <aws/core/internal/RetryStrategyImpl.h>

using namespace Aws::Utils::Logging;
using namespace Aws::Utils::Json;
Expand Down Expand Up @@ -104,6 +105,7 @@ AWSError<CoreErrors> JsonErrorMarshaller::BuildAWSError(const std::shared_ptr<Ht

error.SetResponseHeaders(httpResponse->GetHeaders());
error.SetResponseCode(httpResponse->GetResponseCode());
Aws::Client::Internal::ClassifyUnmodeledTooManyRequests(error);
error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost());
AWS_LOGSTREAM_ERROR(AWS_ERROR_MARSHALLER_LOG_TAG, error);
return error;
Expand Down Expand Up @@ -197,6 +199,7 @@ AWSError<CoreErrors> XmlErrorMarshaller::BuildAWSError(const std::shared_ptr<Htt

error.SetResponseHeaders(httpResponse->GetHeaders());
error.SetResponseCode(httpResponse->GetResponseCode());
Aws::Client::Internal::ClassifyUnmodeledTooManyRequests(error);
error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost());
AWS_LOGSTREAM_ERROR(AWS_ERROR_MARSHALLER_LOG_TAG, error);
return error;
Expand Down Expand Up @@ -522,6 +525,7 @@ AWSError<CoreErrors> RpcV2ErrorMarshaller::BuildAWSError(const std::shared_ptr<H

error.SetResponseHeaders(httpResponse->GetHeaders());
error.SetResponseCode(httpResponse->GetResponseCode());
Aws::Client::Internal::ClassifyUnmodeledTooManyRequests(error);
error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost());
AWS_LOGSTREAM_ERROR(AWS_ERROR_MARSHALLER_LOG_TAG, error);
return error;
Expand Down
2 changes: 2 additions & 0 deletions src/aws-cpp-sdk-core/source/client/AWSXmlClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <aws/core/utils/event/EventStream.h>
#include <aws/core/utils/UUID.h>
#include <aws/core/client/UserAgent.h>
#include <aws/core/internal/RetryStrategyImpl.h>
#include <smithy/tracing/TracingUtils.h>

using namespace Aws;
Expand Down Expand Up @@ -230,6 +231,7 @@ AWSError<CoreErrors> AWSXMLClient::BuildAWSError(const std::shared_ptr<Http::Htt

error.SetResponseHeaders(httpResponse->GetHeaders());
error.SetResponseCode(httpResponse->GetResponseCode());
Aws::Client::Internal::ClassifyUnmodeledTooManyRequests(error);
error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost());
AWS_LOGSTREAM_ERROR(AWS_XML_CLIENT_LOG_TAG, error);
return error;
Expand Down
4 changes: 4 additions & 0 deletions src/aws-cpp-sdk-core/source/client/AdaptiveRetryStrategy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ namespace Aws
StandardRetryStrategy(retryQuotaContainer, maxAttempts)
{}

AdaptiveRetryStrategy::AdaptiveRetryStrategy(long maxAttempts, double transientBackoffBaseSec) :
StandardRetryStrategy(maxAttempts, transientBackoffBaseSec)
{}

bool AdaptiveRetryStrategy::HasSendToken()
{
return m_retryTokenBucket.Acquire(1, m_fastFail);
Expand Down
59 changes: 37 additions & 22 deletions src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <aws/core/client/DefaultRetryStrategy.h>
#include <aws/core/config/AWSProfileConfigLoader.h>
#include <aws/core/config/defaults/ClientConfigurationDefaults.h>
#include <aws/core/internal/RetryStrategyImpl.h>
#include <aws/core/platform/Environment.h>
#include <aws/core/platform/OSVersionInfo.h>
#include <aws/core/utils/StringUtils.h>
Expand Down Expand Up @@ -571,7 +572,7 @@ ClientConfiguration::ClientConfiguration(bool /*useSmartDefaults*/, const char*
Aws::Config::Defaults::SetSmartDefaultsConfigurationParameters(*this, defaultMode, hasEc2MetadataRegion, ec2MetadataRegion);
}

static Aws::String ResolveRetryMode(Aws::String retryMode) {
static Aws::String ResolveRetryMode(Aws::String retryMode, const Aws::String& defaultRetryMode = "standard") {
if (retryMode.empty())
{
retryMode = Aws::Environment::GetEnv("AWS_RETRY_MODE");
Expand All @@ -580,45 +581,49 @@ static Aws::String ResolveRetryMode(Aws::String retryMode) {
{
retryMode = Aws::Config::GetCachedConfigValue("retry_mode");
}
if (Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_NEW_RETRIES_2026").c_str()) == "true" && retryMode.empty())
if (retryMode.empty())
{
retryMode = "standard";
retryMode = defaultRetryMode;
}
return retryMode;
return Aws::Utils::StringUtils::ToLower(retryMode.c_str());
}

std::shared_ptr<RetryStrategy> InitRetryStrategy(int maxAttempts, Aws::String retryMode) {
retryMode = ResolveRetryMode(retryMode);

std::shared_ptr<RetryStrategy> retryStrategy;
if (retryMode == "standard")
if (retryMode == "legacy")
{
retryStrategy = Internal::CreateLegacyRetryStrategy();
}
else if (retryMode == "adaptive")
{
if (maxAttempts < 0)
{
// negative value set above force usage of default max attempts
retryStrategy = Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG);
retryStrategy = Aws::MakeShared<AdaptiveRetryStrategy>(CLIENT_CONFIG_TAG);
}
else
{
retryStrategy = Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG, maxAttempts);
retryStrategy = Aws::MakeShared<AdaptiveRetryStrategy>(CLIENT_CONFIG_TAG, maxAttempts);
}
}
else if (retryMode == "adaptive")
else
{
if (retryMode != "standard")
{
AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "Unknown retry mode \"" << retryMode << "\", using standard retry mode.");
}
if (maxAttempts < 0)
{
// negative value set above force usage of default max attempts
retryStrategy = Aws::MakeShared<AdaptiveRetryStrategy>(CLIENT_CONFIG_TAG);
retryStrategy = Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG);
}
else
{
retryStrategy = Aws::MakeShared<AdaptiveRetryStrategy>(CLIENT_CONFIG_TAG, maxAttempts);
retryStrategy = Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG, maxAttempts);
}
}
else
{
retryStrategy = Aws::MakeShared<DefaultRetryStrategy>(CLIENT_CONFIG_TAG);
}

return retryStrategy;
}
Expand All @@ -645,9 +650,10 @@ static int ResolveConfiguredMaxAttempts()
}

std::shared_ptr<RetryStrategy> InitRetryStrategy(int maxAttempts, Aws::String retryMode, double transientBackoffBaseSec) {
if (Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_NEW_RETRIES_2026").c_str()) != "true")
retryMode = ResolveRetryMode(retryMode);
if (retryMode == "legacy")
{
// Gate is off: ignore service-specific tuning, use default behavior
// Legacy mode ignores service-specific tuning.
return InitRetryStrategy(retryMode);
}

Expand All @@ -658,14 +664,15 @@ std::shared_ptr<RetryStrategy> InitRetryStrategy(int maxAttempts, Aws::String re
maxAttempts = configuredMaxAttempts;
}

// Only standard mode honors a service-specific backoff base; other modes are unaffected,
// so they go through the default-base path.
if (ResolveRetryMode(retryMode) != "standard")
long attempts = static_cast<long>(maxAttempts);
if (retryMode == "adaptive")
{
return InitRetryStrategy(maxAttempts, retryMode);
return Aws::MakeShared<AdaptiveRetryStrategy>(CLIENT_CONFIG_TAG, attempts, transientBackoffBaseSec);
}
if (retryMode != "standard")
{
AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "Unknown retry mode \"" << retryMode << "\", using standard retry mode.");
}

long attempts = static_cast<long>(maxAttempts);
return Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG, attempts, transientBackoffBaseSec);
}

Expand All @@ -674,6 +681,14 @@ std::shared_ptr<RetryStrategy> InitRetryStrategy(Aws::String retryMode)
return InitRetryStrategy(ResolveConfiguredMaxAttempts(), retryMode);
}

namespace Internal
{
std::shared_ptr<RetryStrategy> InitRetryStrategyForDefaultsMode(const Aws::String& defaultsModeRetryMode)
{
return InitRetryStrategy(ResolveRetryMode("", defaultsModeRetryMode));
}
} // namespace Internal

Aws::String ClientConfiguration::LoadConfigFromEnvOrProfile(const Aws::String& envKey,
const Aws::String& profile,
const Aws::String& profileProperty,
Expand Down
Loading
Loading