Skip to content

Commit 195aeb2

Browse files
committed
Revert "Update the RetryPolicy and ShouldRetry customization logic to allow loosening the retry condition. (Azure#5656)"
This reverts commit f1d9552.
1 parent 7e04728 commit 195aeb2

File tree

4 files changed

+31
-184
lines changed

4 files changed

+31
-184
lines changed

sdk/core/azure-core/CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ Thank you to our developer community members who helped to make Azure Core bette
2727
### Other Changes
2828

2929
- [[#5622]](https://github.com/Azure/azure-sdk-for-cpp/pull/5622) Documentation fix for building the SDK with specific OpenSSL version. (A community contribution, courtesy of _[ByteYue](https://github.com/ByteYue)_)
30-
- [[#5515]](https://github.com/Azure/azure-sdk-for-cpp/issues/5515) Add a `ShouldRetry` virtual method to the retry policy to enable customization of service-specific retry logic.
3130

3231
### Acknowledgments
3332

sdk/core/azure-core/inc/azure/core/http/policies/policy.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ namespace Azure { namespace Core { namespace Http { namespace Policies {
420420
* request. Custom implementations of this method that override the retry behavior, should
421421
* handle that error case, if that needs to be customized.
422422
*
423-
* @remark Unless overriden, the default implementation is to always return `false`. The
423+
* @remark Unless overriden, the default implementation is to always return true. The
424424
* non-retriable errors, including those specified in the RetryOptions, remain evaluated
425425
* before calling ShouldRetry.
426426
*

sdk/core/azure-core/src/http/retry_policy.cpp

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ int32_t RetryPolicy::GetRetryCount(Context const& context)
120120

121121
bool RetryPolicy::ShouldRetry(std::unique_ptr<RawResponse> const&, RetryOptions const&) const
122122
{
123-
return false;
123+
return true;
124124
}
125125

126126
std::unique_ptr<RawResponse> RetryPolicy::Send(
@@ -145,27 +145,19 @@ std::unique_ptr<RawResponse> RetryPolicy::Send(
145145
{
146146
auto response = nextPolicy.Send(request, retryContext);
147147

148-
// Are we out of retry attempts?
149-
// Checking this first, before checking the response so that the extension point of
150-
// ShouldRetry doesn't have the responsibility of checking the number of retries (again).
151-
if (WasLastAttempt(m_retryOptions, attempt))
148+
// If we are out of retry attempts, if a response is non-retriable (or simply 200 OK, i.e
149+
// doesn't need to be retried), then ShouldRetryOnResponse returns false.
150+
if (!ShouldRetryOnResponse(*response.get(), m_retryOptions, attempt, retryAfter))
152151
{
152+
// If this is the second attempt and StartTry was called, we need to stop it. Otherwise
153+
// trying to perform same request would use last retry query/headers
153154
return response;
154155
}
155156

156-
// If a response is non-retriable (or simply 200 OK, i.e doesn't need to be retried), then
157-
// ShouldRetryOnResponse returns false. Service SDKs can inject custom logic to define whether
158-
// the request should be retried, based on the response. The default of `ShouldRetry` is
159-
// false.
160-
// Because of boolean short-circuit evaluation, if ShouldRetryOnResponse returns true, the
161-
// overriden ShouldRetry is not called. This is expected, since overriding ShouldRetry enables
162-
// loosening the retry conditions (retrying where otherwise the request wouldn't be), but not
163-
// strengthening it.
164-
if (!ShouldRetryOnResponse(*response.get(), m_retryOptions, attempt, retryAfter)
165-
&& !ShouldRetry(response, m_retryOptions))
157+
// Service SDKs can inject custom logic to define whether the request should be retried,
158+
// based on the response. The default is true.
159+
if (!ShouldRetry(response, m_retryOptions))
166160
{
167-
// If this is the second attempt and StartTry was called, we need to stop it. Otherwise
168-
// trying to perform same request would use last retry query/headers
169161
return response;
170162
}
171163
}
@@ -235,6 +227,12 @@ bool RetryPolicy::ShouldRetryOnResponse(
235227
using Azure::Core::Diagnostics::Logger;
236228
using Azure::Core::Diagnostics::_internal::Log;
237229

230+
// Are we out of retry attempts?
231+
if (WasLastAttempt(retryOptions, attempt))
232+
{
233+
return false;
234+
}
235+
238236
// Should we retry on the given response retry code?
239237
{
240238
auto const& statusCodes = retryOptions.StatusCodes;

sdk/core/azure-core/test/ut/retry_policy_test.cpp

Lines changed: 15 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -125,91 +125,21 @@ class RetryPolicyTest final : public RetryPolicy {
125125
}
126126
};
127127

128-
class RetryPolicyTest_CustomRetry_True final : public RetryPolicy {
128+
class RetryPolicyTest_CustomRetry_False final : public RetryPolicy {
129129
public:
130-
RetryPolicyTest_CustomRetry_True(RetryOptions const& retryOptions) : RetryPolicy(retryOptions) {}
130+
RetryPolicyTest_CustomRetry_False(RetryOptions const& retryOptions) : RetryPolicy(retryOptions) {}
131131

132132
std::unique_ptr<HttpPolicy> Clone() const override
133133
{
134-
return std::make_unique<RetryPolicyTest_CustomRetry_True>(*this);
134+
return std::make_unique<RetryPolicyTest_CustomRetry_False>(*this);
135135
}
136136

137137
protected:
138-
bool ShouldRetry(std::unique_ptr<RawResponse> const&, RetryOptions const&) const override
138+
bool ShouldRetry(std::unique_ptr<RawResponse> const& response, RetryOptions const& retryOptions)
139+
const override
139140
{
140-
return true;
141-
}
142-
};
143-
144-
class RetryPolicyTest_CustomRetry_Throw final : public RetryPolicy {
145-
public:
146-
RetryPolicyTest_CustomRetry_Throw(RetryOptions const& retryOptions) : RetryPolicy(retryOptions) {}
147-
148-
std::unique_ptr<HttpPolicy> Clone() const override
149-
{
150-
return std::make_unique<RetryPolicyTest_CustomRetry_Throw>(*this);
151-
}
152-
153-
protected:
154-
bool ShouldRetry(std::unique_ptr<RawResponse> const&, RetryOptions const&) const override
155-
{
156-
throw TransportException("Short-circuit evaluation means this should never be called.");
157-
}
158-
};
159-
160-
class RetryPolicyTest_CustomRetry_CopySource final : public RetryPolicy {
161-
public:
162-
RetryPolicyTest_CustomRetry_CopySource(RetryOptions const& retryOptions)
163-
: RetryPolicy(retryOptions)
164-
{
165-
}
166-
167-
std::unique_ptr<HttpPolicy> Clone() const override
168-
{
169-
return std::make_unique<RetryPolicyTest_CustomRetry_CopySource>(*this);
170-
}
171-
172-
protected:
173-
bool ShouldRetry(std::unique_ptr<RawResponse> const& response, RetryOptions const&) const override
174-
{
175-
if (response == nullptr)
176-
{
177-
return true;
178-
}
179-
180-
if (static_cast<std::underlying_type_t<Azure::Core::Http::HttpStatusCode>>(
181-
response->GetStatusCode())
182-
>= 400)
183-
{
184-
const auto& headers = response->GetHeaders();
185-
auto ite = headers.find("x-ms-error-code");
186-
if (ite != headers.end())
187-
{
188-
const std::string error = ite->second;
189-
190-
if (error == "InternalError" || error == "OperationTimedOut" || error == "ServerBusy")
191-
{
192-
return true;
193-
}
194-
}
195-
}
196-
197-
if (static_cast<std::underlying_type_t<Azure::Core::Http::HttpStatusCode>>(
198-
response->GetStatusCode())
199-
>= 400)
200-
{
201-
const auto& headers = response->GetHeaders();
202-
auto ite = headers.find("x-ms-copy-source-error-code");
203-
if (ite != headers.end())
204-
{
205-
const std::string error = ite->second;
206-
207-
if (error == "InternalError" || error == "OperationTimedOut" || error == "ServerBusy")
208-
{
209-
return true;
210-
}
211-
}
212-
}
141+
(void)response;
142+
(void)retryOptions;
213143
return false;
214144
}
215145
};
@@ -220,11 +150,10 @@ TEST(RetryPolicy, ShouldRetry)
220150
using namespace std::chrono_literals;
221151
RetryOptions const retryOptions{3, 10ms, 60s, {HttpStatusCode::Ok}};
222152

223-
// The default ShouldRetry implementation is to always return false,
224-
// which means we will retry up to the retry count in the options, unless the status code isn't
225-
// one that is retriable.
153+
// The default ShouldRetry implementation is to always return true,
154+
// which means we will retry up to the retry count in the options.
226155
{
227-
Azure::Core::Context context = Azure::Core::Context();
156+
Azure::Core::Context context = Azure::Core::Context::ApplicationContext;
228157
auto policy = RetryPolicy(retryOptions);
229158

230159
RawResponse const* responsePtrSent = nullptr;
@@ -234,33 +163,7 @@ TEST(RetryPolicy, ShouldRetry)
234163
policies.emplace_back(std::make_unique<RetryPolicy>(policy));
235164
policies.emplace_back(std::make_unique<TestTransportPolicy>([&]() {
236165
auto response = std::make_unique<RawResponse>(1, 1, HttpStatusCode::Ok, "Test");
237-
responsePtrSent = response.get();
238-
retryCounter++;
239-
return response;
240-
}));
241-
242-
Azure::Core::Http::_internal::HttpPipeline pipeline(policies);
243-
244-
Request request(HttpMethod::Get, Azure::Core::Url("https://www.microsoft.com"));
245-
pipeline.Send(request, context);
246-
247-
EXPECT_NE(responsePtrSent, nullptr);
248-
EXPECT_EQ(retryCounter, 3);
249-
}
250-
251-
// If the status code is retriable based on the options, ShouldRetry doesn't get called.
252-
// Testing short-circuit evaluation
253-
{
254-
Azure::Core::Context context = Azure::Core::Context();
255-
auto policy = RetryPolicyTest_CustomRetry_Throw(retryOptions);
256-
257-
RawResponse const* responsePtrSent = nullptr;
258-
int32_t retryCounter = -1;
259166

260-
std::vector<std::unique_ptr<Azure::Core::Http::Policies::HttpPolicy>> policies;
261-
policies.emplace_back(std::make_unique<RetryPolicyTest_CustomRetry_Throw>(policy));
262-
policies.emplace_back(std::make_unique<TestTransportPolicy>([&]() {
263-
auto response = std::make_unique<RawResponse>(1, 1, HttpStatusCode::Ok, "Test");
264167
responsePtrSent = response.get();
265168
retryCounter++;
266169
return response;
@@ -275,73 +178,20 @@ TEST(RetryPolicy, ShouldRetry)
275178
EXPECT_EQ(retryCounter, 3);
276179
}
277180

278-
// If the status code isn't retriable based on the options, only then does ShouldRetry get called.
279-
// Since the default of ShouldRetry is false, we don't expect any retries.
181+
// Overriding ShouldRetry to return false will mean we won't retry.
280182
{
281183
Azure::Core::Context context = Azure::Core::Context();
282-
auto policy = RetryPolicy(retryOptions);
184+
auto policy = RetryPolicyTest_CustomRetry_False(retryOptions);
283185

284186
RawResponse const* responsePtrSent = nullptr;
285187
int32_t retryCounter = -1;
286188

287189
std::vector<std::unique_ptr<Azure::Core::Http::Policies::HttpPolicy>> policies;
288-
policies.emplace_back(std::make_unique<RetryPolicy>(policy));
289-
policies.emplace_back(std::make_unique<TestTransportPolicy>([&]() {
290-
auto response = std::make_unique<RawResponse>(1, 1, HttpStatusCode::Accepted, "Test");
291-
responsePtrSent = response.get();
292-
retryCounter++;
293-
return response;
294-
}));
295-
296-
Azure::Core::Http::_internal::HttpPipeline pipeline(policies);
297-
298-
Request request(HttpMethod::Get, Azure::Core::Url("https://www.microsoft.com"));
299-
pipeline.Send(request, context);
300-
301-
EXPECT_NE(responsePtrSent, nullptr);
302-
EXPECT_EQ(retryCounter, 0);
303-
}
304-
305-
// Overriding ShouldRetry to return true will mean we will retry, when the status code isn't
306-
// retriable based on the options.
307-
{
308-
Azure::Core::Context context = Azure::Core::Context();
309-
auto policy = RetryPolicyTest_CustomRetry_True(retryOptions);
310-
311-
RawResponse const* responsePtrSent = nullptr;
312-
int32_t retryCounter = -1;
190+
policies.emplace_back(std::make_unique<RetryPolicyTest_CustomRetry_False>(policy));
313191

314-
std::vector<std::unique_ptr<Azure::Core::Http::Policies::HttpPolicy>> policies;
315-
policies.emplace_back(std::make_unique<RetryPolicyTest_CustomRetry_True>(policy));
316192
policies.emplace_back(std::make_unique<TestTransportPolicy>([&]() {
317-
auto response = std::make_unique<RawResponse>(1, 1, HttpStatusCode::Accepted, "Test");
318-
responsePtrSent = response.get();
319-
retryCounter++;
320-
return response;
321-
}));
322-
323-
Azure::Core::Http::_internal::HttpPipeline pipeline(policies);
324-
325-
Request request(HttpMethod::Get, Azure::Core::Url("https://www.microsoft.com"));
326-
pipeline.Send(request, context);
327-
328-
EXPECT_NE(responsePtrSent, nullptr);
329-
EXPECT_EQ(retryCounter, 3);
330-
}
331-
332-
// Copy Status Code scenario (non-retriable HTTP status code)
333-
{
334-
Azure::Core::Context context = Azure::Core::Context();
335-
auto policy = RetryPolicyTest_CustomRetry_CopySource(RetryOptions());
336-
337-
RawResponse const* responsePtrSent = nullptr;
338-
int32_t retryCounter = -1;
193+
auto response = std::make_unique<RawResponse>(1, 1, HttpStatusCode::Ok, "Test");
339194

340-
std::vector<std::unique_ptr<Azure::Core::Http::Policies::HttpPolicy>> policies;
341-
policies.emplace_back(std::make_unique<RetryPolicyTest_CustomRetry_CopySource>(policy));
342-
policies.emplace_back(std::make_unique<TestTransportPolicy>([&]() {
343-
auto response = std::make_unique<RawResponse>(1, 1, HttpStatusCode::Conflict, "Test");
344-
response->SetHeader("x-ms-copy-source-error-code", "OperationTimedOut");
345195
responsePtrSent = response.get();
346196
retryCounter++;
347197
return response;
@@ -353,7 +203,7 @@ TEST(RetryPolicy, ShouldRetry)
353203
pipeline.Send(request, context);
354204

355205
EXPECT_NE(responsePtrSent, nullptr);
356-
EXPECT_EQ(retryCounter, 3);
206+
EXPECT_EQ(retryCounter, 0);
357207
}
358208
}
359209

0 commit comments

Comments
 (0)