I use the HttpClientFactory together with Refit to make API calls. I want to use Polly for Retry, Circuit Breaker and Fallback, and while it's easy to set up Retry and Circuit Breaker, I struggle with Fallback, as it can only return a fallback value of type HttpResponseMessage
, but what is being returned is a Refit.ApiResponse
. I tried returning a dummy HttpResponseMessage
, but then Refit breaks as it expects certain things to be present, e.g. the HttpRequestMessage
.
Has anyone successfully returned a custom object as a fallback value when using HttpClientFactory
with Refit?
This is the initial setup with Retry:
PolicyBuilder<HttpResponseMessage>? policyBuilder = Policy<HttpResponseMessage>
.Handle<Exception>();
IEnumerable<TimeSpan>? retryDelays = Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(1), retryCount: 5, fastFirst:true);
AsyncRetryPolicy<HttpResponseMessage>? retryPolicy = policyBuilder.WaitAndRetryAsync(retryDelays, (exception, timeSpan, retryCount, context) =>
{
Debug.WriteLine($"Exception occurred while called Account Service. Retry policy in effect | Retry Attempt: {retryCount} | WaitSeconds: {timeSpan.TotalSeconds}. Exception: {exception.Exception.Message}");
});
This is the circuit breaker:
AsyncCircuitBreakerPolicy<HttpResponseMessage>? circuitBreakerPolicy = policyBuilder
.CircuitBreakerAsync(breakCircuitAfterErrors, TimeSpan.FromMinutes(keepCircuitBreakForMinutes),
(exception, timespan, context) =>
{
// OnBreak, i.e. when circuit state changes to open
Debug.WriteLine(
$"Account Service circuit breaker policy in effect | State changed to Open (blocked). It will remain open for {keepCircuitBreakForMinutes} minutes");
},
(context) =>
{
// OnReset, i.e. when circuit state changes to closed
Debug.WriteLine("Account Service circuit breaker policy in effect | State changed to Closed (normal).");
});
This is the fallback with HttpResponseMessage
, which breaks Refit:
AsyncFallbackPolicy<HttpResponseMessage> fallbackPolicyForCircuitBreaker = Policy<HttpResponseMessage>
.Handle<BrokenCircuitException>()
.FallbackAsync((cancellationToken) =>
{
// In our case we return a null response.
Debug.WriteLine($"The Circuit is Open (blocked). A fallback null value is returned. Try again later.");
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
});
And here I add the policy handlers to the client:
builder.Services.AddHttpClient("AccountService")
.AddPolicyHandler(fallbackPolicyForCircuitBreaker)
.AddPolicyHandler(retryPolicy)
.AddPolicyHandler(circuitBreakerPolicy);