I'm, trying to check a simple RetryForever
of Polly
class Program
{
public static void Main()
{
int i = 0;
var _retryPolicy = Policy
.Handle<Exception>()
.RetryForever();
_retryPolicy.Execute(async () =>
{
Console.WriteLine(i);
i ;
int.Parse("something");
});
Console.ReadLine();
}
}
A you can see I've created a variable i
to track the number of the executions
Excepted Result:
print i
= 0, 1, 2 etc
Actual Result: print i = 0
CodePudding user response:
I've checked your code and you had right, its stops on 0.
But when i removed async keyword (u didnt have any async operation here) the code runs correct.
So, try this:
using Polly;
int i = 0;
var _retryPolicy = Policy
.Handle<Exception>()
.RetryForever();
_retryPolicy.Execute(() =>
{
Console.WriteLine(i);
i ;
int.Parse("something");
return Task.CompletedTask;
});
CodePudding user response:
I might be late to the party but let me share my wisdom.
When you define a policy then you have to know upfront that you want to decorate a sync or an async method/function.
Retry policy for sync method
Policy
.Handle<Exception>()
.RetryForever();
Retry policy for async method
Policy
.Handle<Exception>()
.RetryForeverAsync();
- In the former case you have an
Execute
method which could anticipate- an
Action
(a method without return value) - or an
Func<TResult>
(a method withTResult
typed return value) - and there are a dozen of other overloads
- an
- In the latter case you have an
ExecuteAsync
method which could anticipate- a
Func<Task>
(an async method without return value) - or a
Func<Task<TResult>>
(an async method withTResult
typed return value) - and there are a dozen of other overloads
- a
Retry policy for sync function
Policy<int>
.Handle<Exception>()
.RetryForever();
Retry policy for async function
Policy<int>
.Handle<Exception>()
.RetryForeverAsync();
In these cases your to be decorated code should return an int
.
So the Execute
anticipates a Func<int>
delegate
policy.Execute(() => { ... return 42; });
and the ExecuteAsync
anticipates a Func<Task<int>>
delegate.
await policy.Execute(async () => { ... return Task.FromResult(42); });
Back to your code
Since you did not made any constraint to the return type during the policy definition that's why you could pass a Func
which returns a Task
(Execute(async () => { ...})
So, your Execute
returns a Task
which is not await
ed
Let's await it
await _retryPolicy.Execute(async () =>
{
Console.WriteLine(i);
i ;
int.Parse("something");
});
If you await
the returned Task
then it will throw a FormatException
.
But that Exception is thrown by the await
which is outside of the Execute
's delegate. So, it will NOT trigger a retry.
Option A for fix
_retryPolicy.Execute(() =>
{
Console.WriteLine(i);
i ;
int.Parse("something");
});
By removing async
your delegate will be an Action
which will throw the FormatException
which could trigger the retry policy
Option B for fix
var _retryPolicy = Policy<int>
.Handle<Exception>()
.RetryForeverAsync();
await _retryPolicy.ExecuteAsync(async () =>
{
Console.WriteLine(i);
i ;
int.Parse("something");
});
If you define your policy for async method and you await
the ExecuteAsync
then it will work as well. Why? Because ExecuteAsync
await
s the provided delegate even if you did not define the delegate as async
await _retryPolicy.ExecuteAsync(() =>
{
Console.WriteLine(i);
i ;
int.Parse("something");
return Task.CompletedTask; //This code is never reached
});