I have a workflow like this:
both API methods have the same type of result. I want to implement this with polly policies.
This is my sample code:
var retryPolicy = Policy
.Handle<HttpRequestException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
.RetryAsync(1, async (exception, retryCount) =>
await CallAnotherAPI());
var fallbackPolicy = Policy<HttpResponseMessage>
.Handle<Exception>()
.FallbackAsync((r, c, ct) => throw r.Exception,
async (r, c) =>
{
Log(r.Message);
});
var result = await fallbackPolicy
.WrapAsync(retryPolicy)
.ExecuteAsync(async () =>
{
await CallAPI();
});
but it doesn't work and all the time fallbackPolicy is executed. How can I write the code that if retryPolicy goes true, fallbackPolicy won't be executed?
If I understand your workflow correctly then you don't need the retry policy at all. The Fallback policy is enough for this.
So, let suppose that the CallApi
and CallAnotherApi
are implemented like this:
private static HttpClient client = new HttpClient();
public static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//408");
}
public static async Task<HttpResponseMessage> CallAnotherAPI()
{
var response = await client.GetAsync("http://httpstat.us//500");
response.EnsureSuccessStatusCode();
return response;
}
httpstatus.us
to simulate certain http status codesCallApi
will always fail with Request TimeoutCallAnotherApi
will always throw HttpRequestException
because of the Ensure
method callNow let's see the policy definition and usage:
public static async Task Main(string[] args)
{
var fallbackPolicy = Policy<HttpResponseMessage>
.HandleResult(msg => msg.StatusCode == HttpStatusCode.RequestTimeout)
.FallbackAsync(async (_) => await CallAnotherAPI());
HttpResponseMessage result;
try
{
result = await fallbackPolicy
.ExecuteAsync(async () =>
{
return await CallAPI();
});
}
catch (Exception ex) {
Console.WriteLine(ex.Message); //TODO: replace with logging
throw;
}
Console.WriteLine(result.StatusCode);
}
ExecuteAsync
will throw exception if either the CallApi
or CallAnotherApi
throwsLet's see the different scenarios one-by-one
CallApi
succeedspublic static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//200");
}
Output
OK
CallApi
failspublic static async Task<HttpResponseMessage> CallAPI()
{
var response = await client.GetAsync("http://httpstat.us//500");
response.EnsureSuccessStatusCode();
return response;
}
Output
Response status code does not indicate success: 500 (Internal Server Error).
Then the application crashes because of throw;
CallApi
timeouts and CallAnotherApi
succeedspublic static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//408");
}
public static async Task<HttpResponseMessage> CallAnotherAPI()
{
var response = await client.GetAsync("http://httpstat.us//200");
response.EnsureSuccessStatusCode();
return response;
}
Output
OK
CallApi
timeouts and CallAnotherApi
failspublic static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//408");
}
public static async Task<HttpResponseMessage> CallAnotherAPI()
{
var response = await client.GetAsync("http://httpstat.us//500");
response.EnsureSuccessStatusCode();
return response;
}
Output
Response status code does not indicate success: 500 (Internal Server Error).
Then the application crashes because of throw;