zAnthony
zAnthony

Reputation: 342

Hooking up Polly Policy

Can someone advice why my Policy handle is not handling my WebException error when I know for a fact that the code hit a WebException for a 429 problem? I've been researching this for a while now and need some help.

This is my Polly Policy:

return Policy.Handle<WebException>()
            .WaitAndRetry(15, // We can also do this with WaitAndRetryForever... but chose WaitAndRetry this time.
            attempt => TimeSpan.FromSeconds(0.1 * Math.Pow(2, attempt)), // Back off!  2, 4, 8, 16 etc times 1/4-second
            (exception, calculatedWaitDuration) =>  // Capture some info for logging! if needed
            {
                // This is your new exception handler! 
                Debug.WriteLine("Retry count: " + retries++);
                Debug.WriteLine("Wait Duration: " + calculatedWaitDuration);
            });

I'm using it like this:

 webResponseWaitRetryPolicy.Execute(() =>
        {
            // Make a request and get a response
            UriBuilder builder = new UriBuilder(options.BaseUrl);
                builder.Port = -1;
                var query = HttpUtility.ParseQueryString(builder.Query);
                /// handle parameters
                query["client_key"] = options.ClientKey;
                query["model_id"] = model;
                query["image_url"] = imageUrl;

                builder.Query = query.ToString();
                string url = builder.ToString();
                string content = string.Empty;

                Result objResult;
               HttpWebResponse response = null;


                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.AutomaticDecompression = DecompressionMethods.GZip;
                try
                {
                   response = (HttpWebResponse)request.GetResponse();
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        using (Stream stream = response.GetResponseStream())
                        using (StreamReader reader = new StreamReader(stream))
                        {
                            content = reader.ReadToEnd();
                        }

                        objResult = JsonConvert.DeserializeObject<Result>(content);


                }
                catch(WebException ex)
                {
                    eventualFailures++; 
                    Debug.WriteLine("Failure: " + eventualFailures);


                }
            });

        return objResult;
    }

When I run the code, I can see that it trigger the WebException but the Policy is not being called. Please help.

Upvotes: 0

Views: 1623

Answers (2)

mountain traveller
mountain traveller

Reputation: 8156

Your try {} catch {} is swallowing the thrown exceptions before the Polly policy has the chance to handle them. Where you have:

try
{
    /* snip */
}
catch(WebException ex)
{
    eventualFailures++; 
    Debug.WriteLine("Failure: " + eventualFailures);
}

Use:

try
{
    /* snip */
}
catch(WebException ex)
{
    eventualFailures++; 
    Debug.WriteLine("Failure: " + eventualFailures);
    throw;
}

Explanation: When a catch clause catches an exception and does not rethrow it, the exception is not propagated outside the catch block when the catch block completes. The catch block swallows the exception.

For Polly to handle an exception, the exception needs to be propagated out of the delegate you pass to policy.Execute(() => ), so that it is thrown back on to the policy, which then handles it.


EDIT: The above answer intentionally demonstrates the minimum that needs to be changed from the posted code, to make the Polly policy handle the exception. As Cyrus suggested in the comments, if the sole use of the try/catch is for some extra logging, you can instead do that in the onRetry clause of the Polly policy, and remove the try/catch altogether.


SECOND EDIT: If the concern is that the Polly policy still eventually rethrows the WebException if all retries fail: this is intentional; RetryPolicy signals that all retries have been made without success by rethrowing the final exception.

If you wish to trap that final exception without having to add your own further try/catch, Polly .ExecuteAndCapture(...) can be used for this.

Upvotes: 1

zAnthony
zAnthony

Reputation: 342

I appreciate all the help guys. The problem was that the WebException is a 429 error. If I don't put the try catch methods in there, my code will blow up. So what I end up doing is extend the policy a bit more to look like this.

>    public static Policy<HttpWebResponse> Get429WebResponseWaitRetryPolicy()
        {
            //Retries policy
            return Policy.Handle<WebException>().OrResult<HttpWebResponse>(r => r == null)
                .WaitAndRetry(15, // We can also do this with WaitAndRetryForever... but chose WaitAndRetry this time.
                attempt => TimeSpan.FromSeconds(0.1 * Math.Pow(2, attempt)), // Back off!  2, 4, 8, 16 etc times 1/4-second
                (exception, calculatedWaitDuration) =>  // Capture some info for logging! if needed
                {
                    // This is your new exception handler! 
                    Debug.WriteLine("Retry count: " + retries++);
                    Debug.WriteLine("Wait Duration: " + calculatedWaitDuration);
                });
        }

Then I return the response from the API WebRequest and Polly policy is now able to consume the error thrown and retry. Which look something like this at the end.

Debug.WriteLine("Success: " + eventualSuccesses);
                    return response;
                }
                catch(WebException ex)
                {
                    eventualFailures++; 
                    Debug.WriteLine("Failure: " + eventualFailures);
                    return response;
                 }

Upvotes: 0

Related Questions