Even though it is a later answer it might be helpful for future readers
The policy definitions
var globalTimeoutPolicy = Policy
.TimeoutAsync<EnquiryResult>(TimeSpan.FromMilliseconds(expirationPeriodMilliseconds));
var retryForeverPolicy = Policy
.HandleResult<EnquiryResult>(message => message.Status == EnquiryStatus.SystemError)
.RetryForeverAsync();
var combinedPolicy = Policy.WrapAsync(globalTimeoutPolicy, retryForeverPolicy);
- Here we have defined two policies
- One for retrying the same action over and over again if it receives
SystemError
- Another to terminate the action after N milliseconds
- Finally we have chained/combined the policies into one
- Because the
globalTimeoutPolicy
has been passed first to the WrapAsync
that's why it is the outer policy so this timeout overarches all retry attempts
- If we would pass the
globalTimeoutPolicy
as the second parameter of the WrapAsync
then this timeout constraint would apply for each individual retry attempts
The usage of the chained policies
try
{
var result = await combinedPolicy.ExecuteAsync(
async (ct) => await ratingProvider.Enquire(request, ct), cancellationToken);
Console.WriteLine($"Method has successfully completed with status: '{result.Status}'.");
}
catch(TimeoutRejectedException)
{
Console.WriteLine($"Method has failed after retrying for {expirationPeriodMilliseconds}ms.");
}
- Because your
ratingProvider.Enquire
method anticipates a CancellationToken
that's why we can use Optimistic timeout strategy
- Polly will link together your
cancellationToken
with the TimeoutPolicy's CancellationToken
- If the timeout triggers and all previous retry attempts returned with
SystemError
then the ExecuteAsync
will thrown an TimeoutRejectedException