微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C# 中的 Polly 模式用于工作流? CallApi 成功CallApi 失败CallApi 超时和 CallAnotherApi 成功CallApi 超时和 CallAnotherApi 失败

如何解决C# 中的 Polly 模式用于工作流? CallApi 成功CallApi 失败CallApi 超时和 CallAnotherApi 成功CallApi 超时和 CallAnotherApi 失败

我有一个这样的工作流程:

  • 调用 API 方法
    • 如果抛出任何异常但超时,程序会记录该异常并抛出它。
  • 如果抛出超时,程序必须调用一个 API 方法
    • 调用一个 API 方法后,如果一切正常,程序将返回结果。
    • 否则程序会抛出异常并记录。

两种 API 方法具有相同类型的结果。 我想通过波利政策来实现这一点。

这是我的示例代码

var retryPolicy = Policy
    .Handle<HttpRequestException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
    .RetryAsync(1,async (exception,retryCount) =>
        await CallAnotherAPI());

var fallbackPolicy = Policy<HttpResponseMessage>
    .Handle<Exception>()
    .FallbackAsync((r,c,ct) => throw r.Exception,async (r,c) =>
    {
        Log(r.Message);
    });

var result = await fallbackPolicy
    .WrapAsync(retryPolicy)
    .ExecuteAsync(async () =>
    {
        await CallAPI();
    });

但它不起作用并且一直执行 fallbackPolicy。如何编写如果 retryPolicy 为真,则不会执行 fallbackPolicy 的代码

解决方法

如果我正确理解您的工作流程,那么您根本不需要重试策略。回退策略就足够了。

所以,假设 CallApiCallAnotherApi 是这样实现的:

private static HttpClient client = new HttpClient();
public static async Task<HttpResponseMessage> CallAPI()
{
    return await client.GetAsync("http://httpstat.us//408");
}

public static async Task<HttpResponseMessage> CallAnotherAPI()
{
    var response = await client.GetAsync("http://httpstat.us//500");
    response.EnsureSuccessStatusCode();
    return response;
}
  • 我使用 httpstatus.us 来模拟某些 http 状态代码
  • CallApi 将始终因请求超时而失败
  • CallAnotherApi 将始终抛出 HttpRequestException,因为 Ensure 方法调用

现在让我们看看策略定义和用法:

public static async Task Main(string[] args)
{
    var fallbackPolicy = Policy<HttpResponseMessage>
    .HandleResult(msg => msg.StatusCode == HttpStatusCode.RequestTimeout)
    .FallbackAsync(async (_) => await CallAnotherAPI());

    HttpResponseMessage result;
    try
    {
        result = await fallbackPolicy
            .ExecuteAsync(async () =>
            {
                return await CallAPI();
            });
    }
    catch (Exception ex) {
        Console.WriteLine(ex.Message); //TODO: replace with logging
        throw;
    }

    Console.WriteLine(result.StatusCode);
}
  • 仅当响应的状态代码为 408 时才应触发回退策略
  • ExecuteAsync 将抛出异常,如果 CallApiCallAnotherApi 抛出

让我们一一看看不同的场景

CallApi 成功

public static async Task<HttpResponseMessage> CallAPI()
{
    return await client.GetAsync("http://httpstat.us//200");
}

输出

OK

CallApi 失败

public static async Task<HttpResponseMessage> CallAPI()
{
    var response = await client.GetAsync("http://httpstat.us//500");
    response.EnsureSuccessStatusCode();
    return response;
}

输出

Response status code does not indicate success: 500 (Internal Server Error).

然后应用程序因为throw;

而崩溃

CallApi 超时和 CallAnotherApi 成功

public static async Task<HttpResponseMessage> CallAPI()
{
    return await client.GetAsync("http://httpstat.us//408");
}

public static async Task<HttpResponseMessage> CallAnotherAPI()
{
    var response = await client.GetAsync("http://httpstat.us//200");
    response.EnsureSuccessStatusCode();
    return response;
}

输出

OK

CallApi 超时和 CallAnotherApi 失败

public static async Task<HttpResponseMessage> CallAPI()
{
    return await client.GetAsync("http://httpstat.us//408");
}

public static async Task<HttpResponseMessage> CallAnotherAPI()
{
    var response = await client.GetAsync("http://httpstat.us//500");
    response.EnsureSuccessStatusCode();
    return response;
}

输出

Response status code does not indicate success: 500 (Internal Server Error).

然后应用程序因为throw;

而崩溃

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。