Reputation: 793
I'd like to use Polly to do the following: Attempt a request with a very short timeout. If it fails, retry with a longer timeout.
I see that Retry
can access retryCount
like this:
Policy
.Handle<SomeExceptionType>()
.Retry(3, (exception, retryCount, context) =>
{
// do something
});
And I see that Timeout
can specify an int
or TimeSpan
, like this:
Policy.Timeout(TimeSpan.FromMilliseconds(2500))
I even see that you can pass a function in to the timeout, like this:
Policy.Timeout(() => myTimeoutProvider)) // Func<TimeSpan> myTimeoutProvider
The Func
option seems the most promising, but where could it access the retry count? It's tempting to keep state outside of the policy, but that's dangerous if I ever want to share the policy in a thread safe manner.
Any advice?
Upvotes: 4
Views: 1508
Reputation: 8156
You can use Polly Context
to pass state data between different policies involved in an execution. A unique instance of Polly Context
flows with every Polly execution, so this is entirely thread-safe.
More detail on this technique in this blog post.
For example:
const string RetryCountKey = "RetryCount";
RetryPolicy retryStoringRetryCount = Policy
.Handle<Exception>()
.Retry(3, (exception, retryCount, context) =>
{
Console.WriteLine("Storing retry count of " + retryCount + " in execution context.");
context[RetryCountKey] = retryCount;
});
TimeoutPolicy timeoutBasedOnRetryCount = Policy
.Timeout(context =>
{
int tryCount;
try
{
tryCount = (int) context[RetryCountKey];
}
catch
{
tryCount = 0; // choose your own default for when it is not set; also applies to first try, before any retries
}
int timeoutMs = 25 * (tryCount + 1);
Console.WriteLine("Obtained retry count of " + tryCount + " from context, thus timeout is " + timeoutMs + " ms.");
return TimeSpan.FromMilliseconds(timeoutMs);
});
PolicyWrap policiesTogether = retryStoringRetryCount.Wrap(timeoutBasedOnRetryCount);
(Note: Of course this ^ can be made more concise. Set out here for maximum clarity.)
Here is a live dotnetfiddle example.
Upvotes: 6
Reputation: 1391
From: https://github.com/App-vNext/Polly/wiki/Timeout
int retryCount_ = 0;
Func<TimeSpan> myTimeoutProvider = () =>
TimeSpan.FromMilliseconds(25*retryCount_);
// Configure variable timeout via a func provider.
Policy
.Timeout(() => myTimeoutProvider)) // Func<TimeSpan> myTimeoutProvider
.Retry(3, (exception, retryCount, context) =>
{
retryCount_ = retryCount;
// do something
})
or set the timeout similar to the way shown in:
Policy
.Handle<SomeExceptionType>()
.WaitAndRetry(5, retryAttempt =>
TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
);
UPDATE
You can also hook onto onTimeoutAsync
callback and keep increasing your local variable that myTimeoutProvider
relies on.
Upvotes: 1