I am trying to get the timout Policy to work correctly. I have the following requirement while integrating an api.
For this task I would like to use Polly which seems to me a fantastic component to help handling transient failures. However as I am very new to this technology I just want to be sure if I am implementing correctly.
First of all I have created a timeout policy with Polly like this
var timeoutPolicy =
Policy.TimeoutAsync(
TimeSpan.FromSeconds( 20 ),
TimeoutStrategy.Optimistic,
async ( context, timespan, task ) => {
//write here the cancel request
} );
then after that I am ready to execute the policy
var policyResult = await timeoutPolicy.ExecuteAndCaptureAsync( async () => {
//make here the request 1
} );
What I got from the documentation is that if a timout occurs inside the timeoutPolicy.ExecuteAndCaptureAsync
delegate Polly automagically invoke the onTimeout
delegate. Right?
However my questions are:
What I got from the documentation is that if a timeout occurs inside the ExecuteAndCaptureAsync delegate Polly automagically invoke the onTimeout delegate. Right?
What happens if inside the execute delegate an exception occurs?
Because you are using ExecuteAndCaptureAsync(...), the exception is placed in policyResult.FinalException.
Should I wrap that polly construct in a try catch?
Because you are using ExecuteAndCaptureAsync(..), the exception is placed in policyResult.FinalException, so you don't need a try-catch.
When I analyze the policy result how do I understand if the timeout has happened or not?
TimeoutPolicy throws TimeoutRejectedException on a timeout. Because you are using ExecuteAndCaptureAsync(...), you should find that exception placed in policyResult.FinalException.
A couple of further comments. With TimeoutStrategy.Optimisitic
, which is based on co-operative cancellation by CancellationToken
, you should execute a delegate taking a cancellation token:
var policyResult = await timeoutPolicy.ExecuteAndCaptureAsync(async (ct) => {
//make request 1, in a form which responds to the cancellation token ct
}, userCancellationToken /* CancellationToken.None is acceptable. Polly will merge its timing-out CancellationToken into ct, during policy execution. */
);
Second, as an alternative to invoking the cancel request inside the onRetryAsync: async ( context, timespan, task ) => { ... }
, you have the option to make the code more sequential / less nested with a pattern like below:
var policyResult = await timeoutPolicy.ExecuteAndCaptureAsync(async (ct) => {
//make request 1, in a form which responds to the cancellation token ct
}, CancellationToken.None);
if (policyResult.Outcome == OutcomeType.Failure && policyResult.FinalException is TimeoutRejectedException)
{
//write here the cancel request
}
UPDATE: Invoking the cancel request will work either way - from inside the onRetryAsync
, or sequentially, as just above. An advantage of the sequential version is that it may make it easier to reason about what happens if the cancel request fails with an exception. With the nested approach (cancel request invoked inside onRetryAsync
), an exception finally captured into policyResult.FinalException
could come from either the initial request or the cancel request - and it may be hard to tell which.