如何在ExecuteAsync方法中处理异常?

时间:2017-09-07 00:59:35

标签: c# async-await

我已将Transient Fault Handling Application Block的ExecuteAsync方法包装在重试类中,如下所示:

public class RetryWrapper
{
    public Task IncrementalAsync(Func<Task> action)
    {
        var retryStrategy = new Incremental(3, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2));

        var retryPolicy = new RetryPolicy<AzureServiceBusDetectionStrategy>(retryStrategy);
        retryPolicy.Retrying += (sender, args) =>
        {
            Console.WriteLine("Retry - Count = {0}, Delay = {1}, Exception = {2}",
            args.CurrentRetryCount, args.Delay, args.LastException.Message);
        };

        return retryPolicy.ExecuteAsync(action);
    }
}

从我的客户端函数中,我调用它如下:

RetryWrapper retry = new RetryWrapper();
try
{
    retry.IncrementalAsync<bool>(this.SomeFunction);
}
catch (Exception ex)
{
    Console.WriteLine("All retries failed. Exception details: {0}", ex.ToString());
}

SomeFunction的定义是:

public async Task<bool> SomeFunction()
{
     await Task.Delay(100);
     throw new Exception("Incremental execute task generic");
}

当我运行程序时,它会重试三次,但在最后一次尝试时,不会像ExecuteAction方法那样抛出异常:

Retry - Count = 1, Delay = 00:00:01, Exception = Incremental execute task generic
Retry - Count = 2, Delay = 00:00:03, Exception = Incremental execute task generic
Retry - Count = 3, Delay = 00:00:05, Exception = Incremental execute task generic

如何从ExecuteAync方法重试后捕获异常?另外,使用这样的包装类是否很好?目的是将瞬态块代码集中在一个地方,所以明天我可以切换库。请建议是否有更好的模式。

1 个答案:

答案 0 :(得分:0)

由于异常作为Retrying事件处理程序的事件参数的一部分可用,我猜测重试策略本身正在捕获异常。您可能无法直接在try catch中获取异常,因为策略的内部工作不会重新抛出异常。

但是,您可以为RetryWrapper课程添加一些支持属性。

public class RetryWrapper
{
    private const Int32 RetryTimes = 3;

    // Can be private if you don't need all available to caller.
    public IList<Exception> Exceptions { get; private set; }

    public Exception LastException => Exceptions.LastOrDefault() ?? null;

    public Boolean Failed => Exceptions.Count == _retryTimes;

    public RetryWrapper() {
        Exceptions = new List<Exception>();
    }

    public Task IncrementalAsync(Func<Task> action)
    {
        var retryStrategy = new Incremental(RetryTimes, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2));

        var retryPolicy = new RetryPolicy<AzureServiceBusDetectionStrategy>(retryStrategy);

        retryPolicy.Retrying += (sender, args) =>
        {
            Console.WriteLine("Retry - Count = {0}, Delay = {1}, Exception = {2}",
            args.CurrentRetryCount, args.Delay, args.LastException.Message);
            Exceptions.Add(args.LastException);
        };

        return retryPolicy.ExecuteAsync(action);
    }
}

然后

RetryWrapper retry = new RetryWrapper();
retry.IncrementalAsync<bool>(this.SomeFunction);
if (retry.Failed) 
{
    Console.WriteLine("All retries failed. Exception details: {0}", retry.LastException.Message.ToString());
}