如何在执行 Polly 策略时包含 return 语句?

How to include a return statement when executing a Polly policy?

下面是我在 C# Windows 应用程序中的代码,其中处理了与 Oracle 的连接、FTP 和空引用异常:

public Result Execute()
{
    Result result = null;
    string errorMessage = string.Empty;

    var retryTimes = 1000;
    var retryableErrorCodes = new[] { "ORA-03113", "ORA-03114", "ORA-12543",
        "ORA-12170", "ORA-12154", "ORA-12541", "ORA-12560", "ORA-03135",
        "Connection request timed out" };
    var retryExceptionError = new[] { "Object reference not set to an instance of an object" };

    RetryPolicy retryPolicyFTP = Policy
        .Handle<Xceed.Ftp.FtpInvalidStateException>().Or<Xceed.Ftp.FtpIOException>()
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    RetryPolicy retryPolicyOracle = Policy
        .Handle<OracleException>(ex => retryableErrorCodes.Any(errorCode => ex.Message.ToString().Contains(errorCode)))
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    RetryPolicy retryException = Policy
        .Handle<Exception>(ex => retryExceptionError.Any(errorCode => ex.Message.ToString().Contains(errorCode)))
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    Policy.Wrap(retryPolicyFTP, retryPolicyOracle, retryException).Execute(() =>
    {
        //few lines of C# Code like fetching details from Database
        if(some condition)
        {
            //Some Operations
            return new Result(ResultType.Failure, "This function has Failed");
        }
        if(some other condition)
        {
            //Some Operations
            return new Result(ResultType.Success, "This function is Successful");
        }
        //Some more lines of C# Code
    });
    return Result.Successful;
}

使用这段代码,我不能在函数中间使用 return 关键字,因为 Polly 框架不允许这样做。

您能否建议在函数中间处理 return 关键字的更好方法是什么?

在 Polly 中,您可以为方法和函数定义装饰器。

如果是方法,重试策略应该这样定义:

RetryPolicy retryPolicyFTP = Policy
    .Handle<Xceed.Ftp.FtpInvalidStateException>().Or<Xceed.Ftp.FtpIOException>()
    .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

如果是函数,重试策略应该这样定义:

RetryPolicy<Result> retryPolicyFTP = Policy<Result>
    .Handle<Xceed.Ftp.FtpInvalidStateException>().Or<Xceed.Ftp.FtpIOException>()
    .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

您也应该在此处找到左手和右手上的 <Result> 部分。


有了这些知识,您的方法可以重写为:

public Result Execute()
{
    Result result = null;
    string errorMessage = string.Empty;

    var retryTimes = 1000;
    var retryableErrorCodes = new[] { "ORA-03113", "ORA-03114", "ORA-12543", "ORA-12170", "ORA-12154", "ORA-12541", "ORA-12560", "ORA-03135", "Connection request timed out" };
    var retryExceptionError = new[] { "Object reference not set to an instance of an object" };

    RetryPolicy<Result> retryPolicyFTP = Policy<Result>
        .Handle<Xceed.Ftp.FtpInvalidStateException>().Or<Xceed.Ftp.FtpIOException>()
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    RetryPolicy<Result> retryPolicyOracle = Policy<Result>
        .Handle<OracleException>(ex => retryableErrorCodes.Any(errorCode => ex.Message.ToString().Contains(errorCode)))
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    RetryPolicy<Result> retryException = Policy<Result>
        .Handle<Exception>(ex => retryExceptionError.Any(errorCode => ex.Message.ToString().Contains(errorCode)))
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    Result res = Policy.Wrap(retryPolicyFTP, retryPolicyOracle, retryException).Execute(() =>
    {
        if (some condition)
        {
            return new Result(ResultType.Failure, "This function has Failed");
        }
        if (some other condition)
        {
            return new Result(ResultType.Success, "This function is Successful");
        }
        return Result.Successful;
    });
    return res;
}

因为你的 Execute 必须 return 一个 Result 这就是为什么 Result.Successful 可以移动到 Execute 块内的原因。


我还建议像这样将策略声明和执行分开:

public Result Execute()
{
    ...

    var strategy = Policy.Wrap(retryPolicyFTP, retryPolicyOracle, retryException)
    return strategy.Execute(() =>
    {
        if (some condition)
        {
            return new Result(ResultType.Failure, "This function has Failed");
        }
        if (some other condition)
        {
            return new Result(ResultType.Success, "This function is Successful");
        }
        return Result.Successful;
    });
}