RetryStrategy.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/core/client/RetryStrategy.h>
  6. #include <aws/core/client/AWSError.h>
  7. #include <aws/core/client/CoreErrors.h>
  8. #include <aws/core/utils/Outcome.h>
  9. using namespace Aws::Utils::Threading;
  10. namespace Aws
  11. {
  12. namespace Client
  13. {
  14. static const int INITIAL_RETRY_TOKENS = 500;
  15. static const int RETRY_COST = 5;
  16. static const int TIMEOUT_RETRY_COST = 10;
  17. StandardRetryStrategy::StandardRetryStrategy(long maxAttempts) :
  18. m_retryQuotaContainer(Aws::MakeShared<DefaultRetryQuotaContainer>("StandardRetryStrategy")),
  19. m_maxAttempts(maxAttempts)
  20. {
  21. srand((unsigned int)time(NULL));
  22. }
  23. StandardRetryStrategy::StandardRetryStrategy(std::shared_ptr<RetryQuotaContainer> retryQuotaContainer, long maxAttempts) :
  24. m_retryQuotaContainer(retryQuotaContainer),
  25. m_maxAttempts(maxAttempts)
  26. {
  27. srand((unsigned int)time(NULL));
  28. }
  29. void StandardRetryStrategy::RequestBookkeeping(const HttpResponseOutcome& httpResponseOutcome)
  30. {
  31. if (httpResponseOutcome.IsSuccess())
  32. {
  33. m_retryQuotaContainer->ReleaseRetryQuota(NO_RETRY_INCREMENT);
  34. }
  35. }
  36. void StandardRetryStrategy::RequestBookkeeping(const HttpResponseOutcome& httpResponseOutcome, const AWSError<CoreErrors>& lastError)
  37. {
  38. if (httpResponseOutcome.IsSuccess())
  39. {
  40. m_retryQuotaContainer->ReleaseRetryQuota(lastError);
  41. }
  42. }
  43. bool StandardRetryStrategy::ShouldRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const
  44. {
  45. if (!error.ShouldRetry())
  46. return false;
  47. if (attemptedRetries + 1 >= m_maxAttempts)
  48. return false;
  49. return m_retryQuotaContainer->AcquireRetryQuota(error);
  50. }
  51. long StandardRetryStrategy::CalculateDelayBeforeNextRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const
  52. {
  53. AWS_UNREFERENCED_PARAM(error);
  54. // Maximum left shift factor is capped by ceil(log2(max_delay)), to avoid wrap-around and overflow into negative values:
  55. return (std::min)(rand() % 1000 * (1 << (std::min)(attemptedRetries, 15L)), 20000);
  56. }
  57. DefaultRetryQuotaContainer::DefaultRetryQuotaContainer() : m_retryQuota(INITIAL_RETRY_TOKENS)
  58. {}
  59. bool DefaultRetryQuotaContainer::AcquireRetryQuota(int capacityAmount)
  60. {
  61. WriterLockGuard guard(m_retryQuotaLock);
  62. if (capacityAmount > m_retryQuota)
  63. {
  64. return false;
  65. }
  66. else
  67. {
  68. m_retryQuota -= capacityAmount;
  69. return true;
  70. }
  71. }
  72. bool DefaultRetryQuotaContainer::AcquireRetryQuota(const AWSError<CoreErrors>& error)
  73. {
  74. int capacityAmount = error.GetErrorType() == CoreErrors::REQUEST_TIMEOUT ? TIMEOUT_RETRY_COST : RETRY_COST;
  75. return AcquireRetryQuota(capacityAmount);
  76. }
  77. void DefaultRetryQuotaContainer::ReleaseRetryQuota(int capacityAmount)
  78. {
  79. WriterLockGuard guard(m_retryQuotaLock);
  80. m_retryQuota = (std::min)(m_retryQuota + capacityAmount, INITIAL_RETRY_TOKENS);
  81. }
  82. void DefaultRetryQuotaContainer::ReleaseRetryQuota(const AWSError<CoreErrors>& error)
  83. {
  84. int capacityAmount = error.GetErrorType() == CoreErrors::REQUEST_TIMEOUT ? TIMEOUT_RETRY_COST : RETRY_COST;
  85. ReleaseRetryQuota(capacityAmount);
  86. }
  87. }
  88. }