-1

I'm using Refit, with Polly and Polly.Extensions.Http in an ASP.NET Core Web API to call some external APIs.

I'm trying to add a policy handler using Polly which can retry depending on the body content as the external API I am working with, doesn't use HTTP Status codes to return operation results, but instead puts operation results in a common returned body object. So it will always return 200 OK but then it could indicate it failed with a body that has Success = false and some errors in the Errors property. Here is the response object properties that are always returned:

public abstract class ApiResultResponse 
{
    public string RequestId { get; set; }
    public List<string> Warnings { get; set; }
    public List<Error> Errors { get; set; }
    public bool Success { get; set; }
}

Trying to add an asynchronous retry policy here using the AddPolicyHandler method call.

But I am not sure how to properly create the retryPolicy object with Polly that will create the desired functionality.

services.AddRefitClient<ISomeApi>(refitSettings)
    .ConfigureHttpClient(c => {
        c.BaseAddress = someApiBaseUrl;
    })
    .AddPolicyHandler(retryPolicy)

I want to add this functionality to a bunch of APIs as one common situation is that calling these APIs may result in rate limiting failures, but I need to evaluate the ApiResultResponse object Errors property to determine if the cause was rate limiting for the failure. I want to handle these at a global level and automatically retry, and not handle it downstream in services.

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
xceled
  • 1
  • 1
  • You might also need to consider to use [Circuit Breaker](https://github.com/App-vNext/Polly/wiki/Circuit-Breaker) to avoid sending requests while you are throttled. – Peter Csala Oct 05 '21 at 07:18

1 Answers1

0

With the HandleResult you can specify the trigger, which basis on the decorated method's returned value.

AsyncRetryPolicy<ApiResultResponse> retryPolicy = Policy
       .HandleResult<ApiResultResponse>(r => r.Success == false && r.Errors?.Count > 0)
       .WaitAndRetryAsync(2, _ => TimeSpan.FromSeconds(2));

References: [1], [2]

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
  • .AddPolicyHandler(), to add a policy at the HTTPClient level, only supports an IAsyncPolicy. Handle Result, which is documented in many cases but this one, does not appear to be a solution here. – xceled Oct 07 '21 at 14:05
  • @xceled You should not need to register the `ISomeApi` with the policy (`AddPolicyHandler`). You can surround the downstream API call with the policy inside the `ISomeApi` implementation. – Peter Csala Oct 07 '21 at 15:12
  • @xceled Shall I amend my post to demonstrate what I meant? – Peter Csala Oct 08 '21 at 06:28
  • Yeah, that is the implementation everyone keeps pointing to. I don't want my downstream code to be concerned with retry logic. I want the it to be at the HttpClient level, which is where I already have my other retry logic. – xceled Oct 08 '21 at 16:03
  • @xceled As you said AddPolicyHandler was designed for HttpClient, not for refit. So, there is no built-in solution to register your custom retry during ConfigureServices. – Peter Csala Oct 08 '21 at 16:09
  • @xceled Please check out [this SO thread](https://stackoverflow.com/questions/72370383/using-an-ilogger-in-a-polly-policy-attached-to-a-refit-client) – Peter Csala May 26 '22 at 06:59