Avoid compiler gotchas mixing sync and async execution - App-vNext/Polly GitHub Wiki
âšī¸ This documentation describes the previous Polly v7 API. If you are using the new v8 API, please refer to pollydocs.org.
Avoid code such as:
// Synchronous policy
var policy = Policy
.Handle<Exception>()
.Retry(3);
// NB Bad code: synchronous execution of an async delegate!
var something = await policy.Execute(async () => await DoSomethingAsync());
The compiler will permit the above code to compile, because async
is not strictly part of a method signature; the code resolves to compiling a delegate which happens to return Task<T>
. Polly additionally cannot throw or fail-to-compile for any sync/async mismatch, because both the policy (Retry
) and the execute overload (Execute
) match as synchronous.
Note however that the Polly policy will not govern the full asynchronous execution lifecycle of DoSomethingAsync()
with this code!
All .NET async
methods synchronously return a Task
representing the ongoing execution, when execution hits the first await
statement. When an async delegate such as async () => await DoSomethingAsync()
is run through a synchronous policy.Execute(...)
, the policy only governs that synchronous execution up to the first await
statement returning that Task
.
The asynchronous task continues to execute and may throw, placing the error into the returned Task
. However, the code is then awaiting that Task (await policy.Execute(...)
) outside the policy execution, as synchronous policy execution has already successfully completed synchronously returning the Task
. As the above code is then awaiting a faulted Task
outside the policy execution, the exception will be rethrown without the policy governing it.