Skip to content

Commit dda6a4b

Browse files
authored
Framework for retrying failing HTTP requests (#117)
* Retry support * Adding retry factory decorator * Added retry initializer * Added documentation * Simplified how the back off handler is registered * Made the back off handler private; Added factor support for exp back off
1 parent bc75c65 commit dda6a4b

File tree

8 files changed

+725
-28
lines changed

8 files changed

+725
-28
lines changed

FirebaseAdmin/FirebaseAdmin.Tests/Util/ErrorHandlingHttpClientTest.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,53 @@ public void NoErrorResponseHandler()
216216
() => new ErrorHandlingHttpClient<FirebaseException>(args));
217217
}
218218

219+
[Fact]
220+
public async Task RetryOnErrorResponse()
221+
{
222+
var handler = new MockMessageHandler()
223+
{
224+
StatusCode = HttpStatusCode.ServiceUnavailable,
225+
Response = "{}",
226+
};
227+
var factory = new MockHttpClientFactory(handler);
228+
var args = this.CreateArgs(factory);
229+
args.RetryOptions = this.RetryOptionsWithoutBackOff();
230+
var httpClient = new ErrorHandlingHttpClient<FirebaseException>(args);
231+
232+
var exception = await Assert.ThrowsAsync<FirebaseException>(
233+
async () => await httpClient.SendAndDeserializeAsync<Dictionary<string, string>>(
234+
this.CreateRequest()));
235+
236+
Assert.Equal(ErrorCode.Internal, exception.ErrorCode);
237+
Assert.Equal("Example error message: {}", exception.Message);
238+
Assert.Null(exception.InnerException);
239+
Assert.NotNull(exception.HttpResponse);
240+
Assert.Equal(5, handler.Calls);
241+
}
242+
243+
[Fact]
244+
public async Task RetryOnNetworkError()
245+
{
246+
var handler = new MockMessageHandler()
247+
{
248+
Exception = new HttpRequestException("Low-level network error"),
249+
};
250+
var factory = new MockHttpClientFactory(handler);
251+
var args = this.CreateArgs(factory);
252+
args.RetryOptions = this.RetryOptionsWithoutBackOff();
253+
var httpClient = new ErrorHandlingHttpClient<FirebaseException>(args);
254+
255+
var exception = await Assert.ThrowsAsync<FirebaseException>(
256+
async () => await httpClient.SendAndDeserializeAsync<Dictionary<string, string>>(
257+
this.CreateRequest()));
258+
259+
Assert.Equal(ErrorCode.Unknown, exception.ErrorCode);
260+
Assert.Equal("Network error", exception.Message);
261+
Assert.Same(handler.Exception, exception.InnerException);
262+
Assert.Null(exception.HttpResponse);
263+
Assert.Equal(5, handler.Calls);
264+
}
265+
219266
[Fact]
220267
public async Task Dispose()
221268
{
@@ -256,6 +303,13 @@ private HttpRequestMessage CreateRequest()
256303
};
257304
}
258305

306+
private RetryOptions RetryOptionsWithoutBackOff()
307+
{
308+
var copy = RetryOptions.Default;
309+
copy.BackOffFactor = 0;
310+
return copy;
311+
}
312+
259313
private class TestHttpErrorResponseHandler : IHttpErrorResponseHandler<FirebaseException>
260314
{
261315
public FirebaseException HandleHttpErrorResponse(HttpResponseMessage response, string body)

0 commit comments

Comments
 (0)