当前位置: 首页 > 知识库问答 >
问题:

Polly断路器策略和使用ASP.NET核心API的HttpClient

阚允晨
2023-03-14

我在结合HttpClient设置Polly的断路器时遇到了问题。

具体来说,CircuitBreakerHttpClient用于ASP.NET Core Web API Controller,其链接如下:

>

  • 重试策略:如果出现暂时错误,则对每个请求重试3次。

    cicuit断路器策略:如果所有请求中出现五个瞬态错误,则生效。

    问题所在

    配置Polly重试策略和断路器策略,并对自定义HttpClient,HttpClientService

        public void ConfigureServices(IServiceCollection services)
            {
               services.AddHttpClient();
               services.AddHttpClient<IHttpClientService, HttpClientService>()                                
                            .AddPolicyHandler((service, request) =>
                                HttpPolicyExtensions.HandleTransientHttpError()
                                    .WaitAndRetryAsync(3,
                                        retryCount => TimeSpan.FromSeconds(Math.Pow(2, retryCount)),
                    onRetry: (outcome, timespan, retryCount, context) =>
                                    {
                                        service.GetService<ILog>().Error("Delaying for {delay}ms, then making retry {retry}.",
                                            timespan.TotalMilliseconds, retryCount);
                                    }
                                )
    )
                            )
                           .AddPolicyHandler((service, request) =>                      
                                    HttpPolicyExtensions.HandleTransientHttpError()
                                        //Further external requests are blocked for 30 seconds if five failed attempts occur sequentially.
                                        //Circuit breaker policies are stateful.All calls through this client share the same circuit state.
                                        .CircuitBreakerAsync(5,
                                                     TimeSpan.FromSeconds(30), 
                                                     (result, timeSpan, context)=>
                                                                service.GetService<ILog>().Error("CircuitBreaker onBreak for {delay}ms", timeSpan.TotalMilliseconds),
                                                      context =>
                                                          service.GetService<ILog>().Error("CircuitBreaker onReset")));
    
             }
    

    CarController

    IHttpClientService是在ConfiguReservices的Polly策略中指定的。HttpClientService使用HttpClient

     [ApiVersion("1")]
        [Route("api/v{version:apiVersion}/[controller]")]
        [ApiController]
        public class CarController : ControllerBase
        {
            private readonly ILog _logger;
            private readonly IHttpClientService _httpClientService;
            private readonly IOptions<Config> _config;
    
            public CarController(ILog logger, IHttpClientService httpClientService, IOptions<Config> config)
            {
                _logger = logger;
                _httpClientService = httpClientService;
                _config = config;
            }
    
            [HttpPost]
            public async Task<ActionResult> Post()
            {  
    
                using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
                {
                    string body = reader.ReadToEnd();
    
                        var statusCode = await _httpClientService.PostAsync(
                            "url",
                            new Dictionary<string, string>
                            {
                                {"headerID", "Id"}                           
                            },
                            body);
                        return StatusCode((int)statusCode);               
                }
            }
          }
    
     public class HttpClientService
    {
        private readonly HttpClient _httpClient;
        public HttpClientService(HttpClient client)
        {
            _httpClient = client;
        }
    
        public async Task<HttpStatusCode> PostAsync(string url, Dictionary<string, string> headers, string body)
        {
            using (var content = new StringContent(body, Encoding.UTF8, "application/json"))
            {
                foreach (var keyValue in headers)
                {
                    content.Headers.Add(keyValue.Key, keyValue.Value);
                }
    
                 var request = new HttpRequestMessage(HttpMethod.Post, url)
                                        {
                                            Content = content
                                        };
    
                var response = await _httpClient.SendAsync(request);
    
                response.EnsureSuccessStatusCode();
                return response.StatusCode;
            }
    
        }
    

    ASP.NET核心API 2.2

    更新已更新的SetWaitAndRetryPolicy扩展方法以使用IServiceProvider。

  • 共有1个答案

    严书
    2023-03-14

    断路器策略是有状态的,可以跟踪各个调用的故障率,因此需要长期使用,而不是根据每个请求创建。

    所发布代码中HttpClientFactory上重载的使用方式:

    .AddPolicyHandler((service, request) => HttpPolicyExtensions.HandleTransientHttpError()
        .CircuitBreakerAsync( /* etc */
    

    是制造一个实例的断路器每一个请求,所以断路器从来没有时间建立一个故障状态。

    .AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError()
        .WaitAndRetryAsync(/* etc */))
    .AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError()
        .CircuitBreakerAsync(/* etc */))
    
    var circuitBreaker = HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(/* etc */);
    services.AddHttpClient<IHttpClientService, HttpClientService>()                                
        .AddPolicyHandler((service, request) => circuitBreaker); // By way of example technique: more typically with this overload, there is some more complex logic to select different policies for different kinds of request.
    

    编辑以回答注释中的问题:该实例不必声明static以使其长期存在。它可以在startup.configureservices(...)方法中声明,就在使用之前,如上面的代码示例所示。lambda并在HttpClientFactory上配置它将捕获它并使其长期存在。

    circuitbreaker实例应该在您想要中断的调用之间共享。如果将断路器附加到通过HttpClientFactory声明的特定HttpClient配置,则所有通过该HttpClient配置实例的调用都将共享该断路器,从而共享中断。

    当将断路器与HttpClientFactory一起使用时,这通常意味着您可以在每个子系统上声明一个HttpClient配置(键入或命名),您希望对其进行断路器调用。

    旁注:所选断路器的变种也根据连续故障计数触发。(这里提到的只是一个额外的因素;发布的问题提到了跨请求发生的5个错误,但不是具体连续发生的。)

     类似资料:
    • .NET核心和ASP.NET核心到底有什么区别?

    • 我有以下政策: 我是这样执行政策的: 问题是,当一个动作在开路上执行时,我在断路器回调中没有得到命中。 我希望通过策略放置一个API调用,要处理的异常类型为。政策定义有问题吗?为什么不叫断路器后备?

    • 我和我的朋友在我们的应用编程接口和角客户端上遇到了CORS问题。我们试图建立一个链接,我们正在使用SignalR和客户端(Angular 7)注册自己来接收来自服务器(ASP)的消息。NET核心2.2)。 在浏览器控制台中,我收到以下消息: CORS策略阻止了对来自http://localhost:4200的https://ourEndpoint/坐标中心/谈判的XMLHttpRequest的访问

    • 我目前正在尝试为客户端界面-服务器交互构建一个API。我已经决定使用ASP.NET核心作为API,Nginx作为托管平台(在Ubuntu 18.04上)。由于ASP.NET使用Kestrel,我们设置了一个反向代理,将请求从Nginx转发到Kestrel——也就是托管API的服务器。我们在NGINX服务器上设置了SSL,但是它没有在Kestrel服务器上设置。 简单地说,我不知道如何在 Kestr

    • 0.15 新版功能. 该节文档讲述Scrapy核心API,目标用户是开发Scrapy扩展(extensions)和中间件(middlewares)的开发人员。 Crawler API Scrapy API的主要入口是 Crawler 的实例对象, 通过类方法 from_crawler 将它传递给扩展(extensions)。 该对象提供对所有Scrapy核心组件的访问, 也是扩展访问Scrapy核

    • 谢谢,麦克斯