【问题标题】:Polly log all requests with URL, Headers, Content and ResponsePolly 使用 URL、标头、内容和响应记录所有请求
【发布时间】:2021-02-18 17:19:42
【问题描述】:

我有一个项目从其他项目调用了许多其他 API,并且我遇到了一些问题,不仅要识别这些 API 的错误,还要识别正确的响应,但其他系统上的信息不正确。 我做了这部分,但它只记录重试,我还需要记录成功。

services.AddHttpClient<IClient, Client>("AuthClient", x =>
    {
        x.BaseAddress = new Uri(urlAn);
    }).AddPolicyHandler((services, request) => 
    HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(
    new[]
    {
        TimeSpan.FromSeconds(1),
        TimeSpan.FromSeconds(5),
        TimeSpan.FromSeconds(10)
    },
    onRetry: (outcome, timespan, retryAttempt, context) =>
    {
        services.GetService<ILogger>()
            .LogWarning("Delaying for {delay}ms, then making retry {retry}.", timespan.TotalMilliseconds, retryAttempt);
    }));

【问题讨论】:

  • 这不应该是策略处理程序的关注点。尝试委托处理程序。
  • 谢谢@crowcoder,如果你能举个例子,我把它设置为已回答。

标签: c# .net polly


【解决方案1】:

onRetry 方法仅在出现错误时执行,该错误由策略处理。 HandleTransientHttpError 触发策略

  • 当有HttpRequestException
  • 或当响应代码为 408 或 5xxx 时。

要注入应该在每种情况下执行的逻辑,您需要使用自定义DelegatingHandler。这个扩展点让您可以将自定义代码注入 HttpClient 的管道 (1)。

这是LoggerHandler 的简单实现:

class LoggerHandler: DelegatingHandler
{
    private readonly ILogger<LoggerHandler> _logger;

    public LoggerHandler(ILogger<LoggerHandler> logger)
    {
        _logger = logger;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        try
        {
            var response = await base.SendAsync(request, cancellationToken);
            _logger.LogInformation(response.StatusCode.ToString());
            return response;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Request has failed after several retries");
            throw;
        }
    }
}
  • 如您所见,我们已将记录器注入到处理程序中
    • 如果下游请求完美无缺,我们会在信息级别记录一些事实
    • 如果下游请求出错,我们会在错误级别记录异常

现在,让我们把所有东西都连接起来:

var retryPolicy = HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(
    new[]
    {
        TimeSpan.FromSeconds(1),
        TimeSpan.FromSeconds(5),
        TimeSpan.FromSeconds(10)
    });

services.AddHttpClient<IClient, Client>("AuthClient", x => { x.BaseAddress = new Uri(urlAn); })
    .AddPolicyHandler(retryPolicy)
    .AddHttpMessageHandler<LoggerHandler>();

请注意注册顺序问题。

  • 请查看SO topic了解更多详情。

还有一些小事情可以改进:

  • 您不必指定HttpClient 的名称,因为您使用的是Typed-Client。
    • services.AddHttpClient&lt;IClient, Client&gt;(x =&gt; ...)
  • 我强烈建议使用比IClientClient 更好的命名。想象一下您需要向您的应用程序添加一个客户端的情况。怎么命名呢? AuthClient 可能是一个更好的名字:
    • services.AddHttpClient&lt;IAuthClient, AuthClient&gt;(x =&gt; ...)
  • 我还鼓励您使用jitter 为您的重试睡眠时间添加随机性。如果所有客户端都尝试对过载的服务器执行重试,那么它将无助于下游。
    • 尝试通过抖动分配重试。
  • 我还建议阅读这篇关于重试、超时和 DelegatingHandler 的 article

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-26
    • 2013-07-06
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 2019-10-04
    • 1970-01-01
    相关资源
    最近更新 更多