重试请求时如何调用 x-HttpMessageHandlers?

问题描述 投票:0回答:2

简而言之:我想在重试请求时执行x-HttpMessageHandlers。

实现:目前我添加了一个HttpClient,该请求由Logging-和PolicyHandler处理:

builder.services.AddHttpClient()
    .AddHttpMessageHandler<LoggingHandler>()
    .AddPolicyHandler(GetRetryPolicy());

政策:为了使政策非常简单,让我们使用一个示例:

public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    // HandleTransientHttpError: Handles HttpRequestException, 
    // Http status codes >= 500 (server errors) 
    // and status code 408 (request timeout)

    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .RetryAsync(3); // Retry the request up to 3 times
}

来源:https://github.com/App-vNext/Polly.Extensions.Http/blob/master/README.md

如果您想测试重试策略,请将请求发送至:https://httpbin.org/status/503

上面的链接将返回一个不成功的 HttpResponseMessage,状态代码为 502。坏网关。

c# asp.net-core-webapi dotnet-httpclient polly retry-logic
2个回答
1
投票

TL; DR:您只需更改消息处理程序注册顺序

来自

.AddHttpMessageHandler<LogHandler>()
.AddPolicyHandler(retryPolicy);

.AddPolicyHandler(retryPolicy)
.AddHttpMessageHandler<LogHandler>();

更新#1

为了更好地理解为什么

DelegatingHandler
的注册顺序很重要,我将扩展我原来的帖子。

AddPolicyHandler

此扩展方法基本上将

PolicyHttpMessageHandler
实例注册到处理程序管道中。该类以将策略应用于传出请求的方式实现
DelegatingHandler
抽象类。 这就是为什么策略类型应该是
IAsyncPolicy<HttpResponseMessage>

这里重要的是,从

HttpClient
的角度来看,你的
LogHandler
和这个
PolicyHttpMessageHandler
以同样的方式对待。

AddHttpMessageHandler
AddPolicyHandler

如果您像您一样将处理程序注册到 HttpClient 的管道中,那么输出将是:

Loghandler
Retry attempt 1
Retry attempt 2

让我们看看幕后发生了什么

我使用 mermaid.js 来绘制此图,并且我使用自动编号来能够关联操作和发出的输出。

2: Loghandler
7: Retry attempt 1
10: Retry attempt 2

AddPolicyHandler
,
AddHttpMessageHandler

这次我们交换一下注册顺序。输出将是:

Loghandler
Retry attempt 1
Loghandler
Retry attempt 2
Loghandler

动作顺序:

最后是相关日志:

4: Loghandler
8: Retry attempt 1
10: Loghandler
14: Retry attempt 2
16: Loghandler

欲了解更多详情,请查看这个SO主题

在这里你可以找到一个 dotnet fiddle 来玩它。


0
投票

将您的日志记录集成到策略中。这是一个简单的示例。

您的计划

var retryPolicy = Policy
    .Handle<HttpRequestException>()
    .OrResult<HttpResponseMessage>(response => !response.IsSuccessStatusCode)
    .WaitAndRetryAsync(2, retryCount => TimeSpan.FromSeconds(2),
        onRetry: (outcome, timespan, retryCount, context) =>
        {
            var logHandler = new LogHandler();
            logHandler.LogRetryAttempt(outcome, retryCount);
        });

您的日志处理程序

public class LogHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        Debug.WriteLine("LogHandler");
        var response = await base.SendAsync(request, cancellationToken);
        return response;
    }

    // Add this method to log retry attempts
    public void LogRetryAttempt(DelegateResult<HttpResponseMessage> outcome, int retryCount)
    {
        // Log the details of the retry attempt
        if (outcome.Exception != null)
        {
            Debug.WriteLine($"Retry {retryCount} due to an exception: {outcome.Exception.Message}");
        }
        else if (outcome.Result != null)
        {
            Debug.WriteLine($"Retry {retryCount} due to a non-success status code: {outcome.Result.StatusCode}");
        }
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.