I'm implementing Polly to retry requests in my C# web app. My sample code is included in this post. The code works as expected but the last parameter passed to CreateFile()
(currently hard-coded as 0) needs to be the value of retryAttempt
. How can I get the value of retryAttempt
within the Execute
's Action?
return Policy
.Handle<HttpException>(x => x.StatusCode == (HttpStatusCode)429)
.Or<StorageException>()
.WaitAndRetry(maxRetryCount, retryAttempt => TimeSpan.FromMilliseconds(Math.Pow(retryIntervalMs, retryAttempt)))
.Execute(() => CreateFile(fileContent, containerName, fileName, connectionString, 0));
Polly does not provide an .Execute(...)
overload where retry count is one of the input parameters to the delegate passed to .Execute(...)
. This is because retry is only one of many Polly policies, whereas the shape of .Execute(...)
overloads must be general to all policy types.
For the use case described in the question, simply:
int count = 0;
return Policy
.Handle<HttpException>(x => x.StatusCode == (HttpStatusCode)429)
.Or<StorageException>()
.WaitAndRetry(maxRetryCount, retryAttempt => TimeSpan.FromMilliseconds(Math.Pow(retryIntervalMs, retryAttempt)))
.Execute(() => CreateFile(fileContent, containerName, fileName, connectionString, count++));
An alternative approach uses Polly's execution-scoped Polly.Context
: an instance of this travels with each execution, and is available to all parts of an execution.
Retry policy already passes the retry count to the onRetry
delegate, so the policy can capture this into the execution-scoped Context
:
var retryPolicyCapturingCountIntoContext =
Policy
.Handle<HttpException>(x => x.StatusCode == (HttpStatusCode)429)
.Or<StorageException>()
.WaitAndRetry(
maxRetryCount,
retryAttempt => TimeSpan.FromMilliseconds(Math.Pow(retryIntervalMs, retryAttempt)),
onRetry: (response, delay, retryCount, context) =>
{
context["retrycount"] = retryCount;
});
In the delegate executed through the policy, we can pick the retry count out of Context
(taking care to handle the case when no retries have yet happened):
retryPolicyCapturingCountIntoContext
.Execute(context =>
{
int retryCount = (context.TryGetValue("retrycount", out var retryObject) && retryObject is int count) ? count : 0;
CreateFile(fileContent, containerName, fileName, connectionString, retryCount);
}, new Context());
If you prefer to avoid the noise of the context.TryGetValue(...)
defensive code, you can alternatively choose to ensure you always initialise context["retrycount"]
before you start an execution:
var myContext = new Polly.Context { {"retrycount ", 0} };
retryPolicyCapturingCountIntoContext
.Execute(
context => CreateFile(fileContent, containerName, fileName, connectionString, (int)context["retrycount"]),
myContext);
For users who want to capture the retry count of each retry as it happens, say for logging, see the Polly retry examples showing how retryCount
is passed as an input parameter to the onRetry
delegate which can be configured on the policy. Further examples here.
For users who want to capture the overall number of retries used for an operation to succeed, in a generalised way - say for telemetry as part of some general execution-dispatch infrastructure code - see these examples in Steve Gordon's blog, which use the Context
-based approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With