Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Polly framework CircuitBreakerAsync does not retry if exception occur

I am using Polly framework for transient fault handling. For synchronous operations Polly circuit breaker policy works fine but when I created its async version it does not retries the execution. Kindly suggest :

Asynchronous method:

private async static Task HelloWorld()
    {
        if (DateTime.Now < programStartTime.AddSeconds(10))
        {
            Console.WriteLine("Task Failed.");
            throw new TimeoutException();
        }
        await Task.Delay(TimeSpan.FromSeconds(1));
        Console.WriteLine("Task Completed.");
    }

Polly circuit breaker async policy:

private static void AsyncDemo3(Func<Task> action)
    {
        programStartTime = DateTime.Now;

        Policy policy = Policy
            .Handle<TimeoutException>()
            .CircuitBreakerAsync(3, TimeSpan.FromSeconds(2));
        try
        {
            var a = policy.ExecuteAndCaptureAsync(action, true).GetAwaiter().GetResult();
        }
        catch (AggregateException ex)
        {
            Console.WriteLine("Exception: " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception: " + ex.Message);
        }
    }

Executing the Polly circuit breaker policy :

AsyncDemo3(HelloWorld);

Kindly help the find and resolve the problem.

like image 601
Demon Hunter Avatar asked Apr 04 '16 09:04

Demon Hunter


2 Answers

I believe you misunderstood what the circuit breaker policy does.

What it does is that if you call it the given number of times and it fails each time, then it will stop calling the given method for a certain amount of time. But it does not retry by itself.

So to do what I think you want to do, you need to combine retry policy with circuit breaker policy. One way to do that would be:

Policy retryPolicy = Policy.Handle<TimeoutException>().RetryAsync(3);

Policy circuitBreakerPolicy = Policy
    .Handle<TimeoutException>()
    .CircuitBreakerAsync(3, TimeSpan.FromSeconds(2));

try
{
    retryPolicy.ExecuteAsync(() => circuitBreakerPolicy.ExecuteAsync(action, true))
        .GetAwaiter().GetResult();
}
…

The output of this code is:

Task Failed.
Task Failed.
Task Failed.
Exception: The circuit is now open and is not allowing calls.
like image 66
svick Avatar answered Oct 11 '22 07:10

svick


Recommend creating both policies and combining the same using PolicyWrap as follows.

Policy Creation

 var circuitBreakerPolicy = Policy
        .Handle<TimeoutException>()
        .CircuitBreakerAsync(3, TimeSpan.FromSeconds(2));
 var retryPolicy = Policy.Handle<TimeoutException>().RetryAsync(3);

 // Combined policy: outermost first, innermost last
 var policy = Policy.WrapAsync(retryPolicy, circuitBreakerPolicy);

Policy Usage

 await this.policy.ExecuteAsync(async () => await SomeFooMethodAsync(cancellationToken));
like image 35
user3613932 Avatar answered Oct 11 '22 09:10

user3613932