Home > Software engineering >  Polly: Is there any way/method in WaitAndRetryAsync that can be treat as RetryCompleted?
Polly: Is there any way/method in WaitAndRetryAsync that can be treat as RetryCompleted?

Time:10-05

I have a query - Could you help me If have completed the number RetryCount in WaitAndRetryAsync but still not getting StatusCode.OK. Then I want to through the exception. So How can I do this?

Or is there any way if a number or retry count is completed, so is there any way that can provide functionality OnRetryComplete so that we can give any message that we have retried multiple times but not able to get the success code and can return any method.

var policy = Policy
        .Handle<Exception>()
        .OrResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
        .WaitAndRetryAsync(2, _ => TimeSpan.FromMilliseconds(200));
try
{
    int count = 0;
    var responseMessage = await asyncPolicy.ExecuteAsync(async () =>
    {
        string requestJson = JsonSerializer.Serialize(eligRequest, new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        });
        using var content = new StringContent(requestJson, Encoding.UTF8, "application/json");
        HttpResponseMessage result = await httpClient.PostAsync("test/api/ate", content);

        return result.EnsureSuccessStatusCode();
    });
    return responseMessage;
}
catch (HttpRequestException error)
{
    logger.LogError("{exceptionMessage}", error.Message);
    throw new CustomException();
}

CodePudding user response:

Polly itself throws that exception out if it is not able to complete the operation within the given retry count and time.

public async Task Main()
{
    var httpClient = new HttpClient();

    AsyncRetryPolicy _retryPolicy;

    _retryPolicy = Policy.Handle<Exception>()
                    .WaitAndRetryAsync(2, retryAttempt =>
                    {
                        Console.WriteLine("Attempt... "   retryAttempt);
                        var timeToRetry = TimeSpan.FromSeconds(2);
                        Console.WriteLine($"Waiting {timeToRetry.TotalSeconds} seconds");
                        return timeToRetry;
                    });

    try
    {
        await _retryPolicy.ExecuteAsync(async () =>
        {
            var response = await httpClient.GetAsync("https://urlnotexist.com/api/products/1");
            response.EnsureSuccessStatusCode();
        });
    }
    catch (Exception ex)
    {
        Console.WriteLine("Final Throw");
        //Validate your logic here and throw ex.
    }
}

The above code will generate output as below:

Attempt... 1
Waiting 2 seconds
Attempt... 2
Waiting 2 seconds
Final Throw

So in the catch block, you will get the exception. From there you can validate your logic and throw it further or log it.

CodePudding user response:

I think you are looking for ExecuteAndCaptureAsync and PolicyResult.

PolicyResult exposes several useful properties to deal with the thrown exception:

  • Outcome: It is Failure if all retries failed without success
  • FinalException: The original exception which was thrown by the decorated code
PolicyResult<string> result = await policy.ExecuteAndCaptureAsync(async () => await ...);
if(result.Outcome == OutcomeType.Failure && result.FinalException != null)
{
    throw new CustomException();
}

Please also change your Policy to indicate that in case of success you want to return with a string:

var policy = Policy<string>
        .Handle<Exception>()
        .OrResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
        .WaitAndRetryAsync(2, _ => TimeSpan.FromMilliseconds(200));
  • Related