Reputation: 342
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
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
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