Pure.Krome
Pure.Krome

Reputation: 86987

When running a Polly Policy in a .NET Core application, it hangs after the exception is caught

I'm trying to test out some Polly "retry" code I have in a basic .NET Core application. I have to implement an async method (via the inherited Interface):

public Task AddMessageAsync( ... ) { .. }

Notice how the method above is NOT decorated with the async keyword? I did that on purpose.

When I try and connect to the 3rd party service (a RabbitMQ server) where I've made hostname of this service, incorrect/typo'd, my sync code tries and fails and throws an exception. Great! but after that, the code just hangs? I thought that the code should just keep retrying.

private static Policy CheckRabbitMQPolicy(ILogger logger)
{
    return Policy
        .Handle<Exception>()
        .WaitAndRetry(15, _ => TimeSpan.FromSeconds(2), (exception, timeSpan, __) => logger.LogWarning(...));
}

public Task AddMessageAsync(string content,
                            TimeSpan? timeToLive,
                            TimeSpan? initialVisibilityDelay,
                            CancellationToken cancellationToken)
{
    CheckRabbitMQPolicy(_logger).Execute(() =>
    {
        using (var connection = _factory.CreateConnection())
        {
            .... // snipped //
        }
    });

    return Task.CompletedTask;
}

So I thought that I could just return a Task.CompletedTask; because there is no code called in this method that is async/await. But when the exception is thrown, it's handled (the log.Warning(..) is called / breaked-on if there's a breakpoint there), but then hangs.

How can I debug what's going on here?

Edit

As per @jeremy-thompson 's reply below, I thought I might try changing the code to:

var policyResult = CheckRabbitMQPolicy(_logger).ExecuteAndCapture(() =>
{
    using (var connection = _factory.CreateConnection())
    {
        .... // snipped //
    }
});


return policyResult.Outcome == OutcomeType.Successful
    ? Task.CompletedTask
    : Task.FromException(policyResult.FinalException);

So this then:

This is a little bit closer, but still doesn't keep retrying 14 more times.

Upvotes: 4

Views: 1498

Answers (1)

DoubleTrouble
DoubleTrouble

Reputation: 902

You should always try to present a minimum working example in the question that demonstrates the problem you're facing. I took your code and tried to make it a running example but everything seems to work as expected. It reties 14 times and it doesn't hang as you describe.

Perhaps by simplifying your code in a similar way you can figure out what's wrong in your case. Good luck!

class Program
{
    static void Main()
    {
        var msg = new MyMessageClass();
        msg.AddMessageAsync("content", TimeSpan.MaxValue, TimeSpan.MaxValue, new CancellationToken());
    }
}

class MyMessageClass
{
    readonly ILogger _logger = NLog.LogManager.GetCurrentClassLogger();
    private static Policy CheckRabbitMQPolicy(ILogger logger)
    {
        return Policy
            .Handle<Exception>()
            .WaitAndRetry(14, _ => TimeSpan.FromSeconds(2),
                (exception, timeSpan, __) =>
                {
                    logger.Warn(exception.Message);
                });
    }
    public Task AddMessageAsync(string content,
        TimeSpan? timeToLive,
        TimeSpan? initialVisibilityDelay,
        CancellationToken cancellationToken)
    {
        var policyResult = CheckRabbitMQPolicy(_logger).ExecuteAndCapture(() => throw new Exception("Connection error"));

        return policyResult.Outcome == OutcomeType.Successful
            ? Task.CompletedTask
            : Task.FromException(policyResult.FinalException);
    }
}

Upvotes: 2

Related Questions