Timeout not working as expected [EDIT: Async pessimistic timeout does not timeout synchronous delegates]
See original GitHub issuePlease clarify if I am misunderstanding how the Timeout Policy works. I would expect this to cause a TimeoutRejectedException but it does not. I have a Task.Delay(4000).Wait() defined in the func that Polly executes. I would think that anything in that Func that takes longer than the specified Timeout would throw TimeoutRejectedException but this is not the behavior I’m seeing.
Taken from Polly samples
// Define our timeout policy: time out after 2 seconds. We will use the pessimistic timeout strategy, which forces a timeout - even when the underlying delegate doesn't support it.
var timeoutPolicy = Policy
.TimeoutAsync(
TimeSpan.FromSeconds(2),
TimeoutStrategy.Pessimistic,
onTimeoutAsync: (callContext, span, task) =>
{
return Task.CompletedTask;
}
);
// Define our waitAndRetry policy: keep retrying with 4 second gaps. This is (intentionally) too long: to demonstrate that the timeout policy will time out on this before waiting for the retry.
var waitAndRetryPolicy = Policy
.Handle<Exception>() // Exception filtering! We don't retry if the inner circuit-breaker judges the underlying system is out of commission!
.WaitAndRetryForeverAsync(
// attempt => TimeSpan.FromSeconds(4),
attempt => TimeSpan.FromMilliseconds(100),
(exception, calculatedWaitDuration) =>
{
});
FallbackPolicy<String> fallbackForAnyException = Policy<String>
.Handle<Exception>()
.FallbackAsync(
fallbackAction: /* Demonstrates fallback action/func syntax */ async ct =>
{
},
onFallbackAsync: async e =>
{
}
);
PolicyWrap<String> policyWrap = fallbackForAnyException.WrapAsync(timeoutPolicy).WrapAsync(waitAndRetryPolicy);
while (!Console.KeyAvailable && !cancellationToken.IsCancellationRequested)
{
try
{
Func<CancellationToken, Task<string>> foo = (ct) =>
{
//shouldn't this cause a TimeoutRejectedException???
Task.Delay(4000).Wait();
return Task.FromResult("hello");
};
string msg = await policyWrap.ExecuteAsync(foo, cancellationToken);
}
catch (Exception e)
{
}
// Wait half second
// await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken);
}
Issue Analytics
- State:
- Created 6 years ago
- Comments:9 (6 by maintainers)
Top Results From Across the Web
c# - How to enable timeout policy with polly
Pessimistic mode with asynchronous policies is intentionally designed only to govern delegates which conform to the normal async pattern. ...
Read more >Polly 7.2.4
Pessimistic timeout allows calling code to 'walk away' from waiting for an executed delegate to complete, even if it does not support cancellation....
Read more >On awaiting a task with a timeout in C# - The Old New Thing
Say you have an awaitable object, and you want to await it, but with a timeout. How would you build that? What you...
Read more >Running an async task with a timeout
I wrote a function async(timeoutAfter:work:). Its goal is to run an async task with a timeout. If the timeout expires and the work...
Read more >Concise handling of async tasks with timeouts in c# - ...
The sync and async codes are handled differently so you have to be ... The Timeout policy can work in two modes: optimistic...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@udlose Let us know (after Thanksgiving!) if we can help any further on this. Re your question:
… there could be two senses.
(1) Per previous comment, a
TimeoutRejectedException
is thrown back onto the code placing the call throughTimeoutPolicy
. (2) If the question is what happened to the task being executed (which was timed out…) : inTimeoutStrategy.Optimistic
, that task should honour theCancellationToken
and thus cancel itself (it won’t continue running). If it wants to pass information back to the calling code about its state at the time of cancellation, that could be done by throwing a customOperationCanceledException
containing extra information. That exception is already passed back to calling code as the inner exception of theTimeoutRejectedException
. If we extend Polly per #338, that exception would also be passed toonTimeout/Async
, which might be a better place eg to capture info for logging.Np. Re:
Agreed. There was a trade-off at design time.
TimeoutStrategy.Pessimistic
works for your sample code, but it is more expensive in terms of resource consumption (especially for the sync case). We madeTimeoutStrategy.Optimistic
the default case, since it seemed good practice to encourage developers towards co-operative cancellation byCancellationToken
(which consumes less resource), rather than making the sledge-hammer version (TimeoutStrategy.Pessimistic
) the default - which also has (for users to grok) complications about how to catch errors from the walked-away-fromTask
s. (Edit: in case this seems like magic information to anyone coming later to the thread, it is all covered in more detail in the doco.)That’s just to explain the rationale of the decision (why your case doesn’t work as the default), but I agree: it makes for this speedbump on learning how to use the policy.