首页 > 解决方案 > 重试机制捕获异常将不起作用

问题描述

如果发生规定的业务逻辑,我正在为 API 调用实现重试机制以发出相同的请求。我现在让它变得非常简单,稍后会通过异常类型处理等来增强它。如果逻辑发生,我只需抛出异常并在重试机制中捕获它们,但在下面的代码只是杀死线程并且在第一次尝试后不执行. 你能帮我请我在这里缺少什么吗?

这是我尝试使用的重试逻辑。

    public static T Do<T>(Func<T> action, TimeSpan retryInterval, int attemptCount)
    {
        var exceptions = new List<Exception>();

        for (int attempted = 0; attempted < attemptCount; attempted++)
        {
            try
            {
                if (attempted > 0)
                {
                    Thread.Sleep(retryInterval);
                }
                return action();
            }
            catch (Exception ex)
            {
                exceptions.Add(ex);
            }
        }
        throw new AggregateException(exceptions);
    }

这就是我调用重试方法的方式。

    await Task.Run(() =>
                {
                    RetryHelper.Do(() => ConfirmRequestRetryAsync(request, true), TimeSpan.FromSeconds(60), 10);
                });

这是由于逻辑而可能引发异常的方法。

    public async void ConfirmRequestRetryAsync(ConfirmRequest request, bool flag)
    {
        logger.Info($"Confirm Request Async Called for the request : {JsonConvert.SerializeObject(request)}");
        var confirmRequest = GetSignedConfirmRequest(request.PaymentId);
        var confirmResponse = await MakeRequest(confirmRequest);
        //Added flag and sending at false at first try to not throw exception
        //Then in retry mechanism this exceptions will be use to trigger retry logic.
        if (flag)
        {
            var statu = ConfirmResponseXmlConvert(confirmResponse);
            if (statu.Item1 == "0" && statu.Item2 == "InProcess")
            {
                throw new Exception("InProcess");
            }
            else if (statu.Item1 == "-1" && statu.Item2 != "Declined")
            {
                throw new Exception("Error");
            }
        }
    }

标签: c#.netasp.net-web-api

解决方案


ConfirmRequestRetryAsync是一个异步 void 方法。这意味着它将在第一次等待时返回。其余代码将在稍后运行,在与调用者相同的线程上下文中。因此,当抛出异常时,重试方法已经返回,并且没有任何东西可以捕获异常。

修复方法是使其成为异步任务方法,并在您的重试方法中等待它。这可能需要重试方法的两种变体,一种用于异步方法,一种用于非异步。

async void 的经验法则是永远不允许从它们中抛出异常,因为任何人都不可能捕获它们。如果可能出现异常,请始终使用异步任务。


推荐阅读