.net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池

这篇具有很好参考价值的文章主要介绍了.net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

public class HttpClientPool : IDisposable
{
    private readonly ConcurrentQueue<HttpClient> _httpClientPool; // HttpClient 对象池
    private readonly SemaphoreSlim _semaphore; // 控制同时访问 HttpClient 对象池的线程数
    private readonly TimeSpan _timeout; // 获取 HttpClient 的超时时间
    private readonly int _maxRetries; // 最大重试次数
    private readonly TimeSpan _circuitBreakerTimeout; // 熔断器超时时间
    private readonly int _consecutiveFailuresThreshold; // 连续失败阈值

    private bool _circuitBreakerTripped; // 熔断器是否触发
    private DateTime _circuitBreakerTrippedTime; // 熔断器触发时间
    private int _consecutiveFailures; // 连续失败计数器

    public HttpClientPool(int maxPoolSize, // 最大 HttpClient 对象池大小
        TimeSpan timeout, // 获取 HttpClient 的超时时间
        int maxRetries, // 最大重试次数
        TimeSpan circuitBreakerTimeout, // 熔断器超时时间
        int consecutiveFailuresThreshold // 连续失败阈值
    )
    {
        _httpClientPool = new ConcurrentQueue<HttpClient>();
        _semaphore = new SemaphoreSlim(maxPoolSize);
        _timeout = timeout;
        _maxRetries = maxRetries;
        _circuitBreakerTimeout = circuitBreakerTimeout;
        _consecutiveFailuresThreshold = consecutiveFailuresThreshold;
        _circuitBreakerTripped = false;
    }

    public async Task<HttpResponseMessage> SendRequestWithRetries(string url)
    {
        var retryCount = 0;
        _consecutiveFailures = 0;

        while (retryCount <= _maxRetries)
        {
            try
            {
                var httpClient = await GetHttpClientAsync();
                var response = await httpClient.GetAsync(url);

                if (response.IsSuccessStatusCode)
                {
                    _consecutiveFailures = 0; // 重置连续失败计数器
                    return response;
                }
                else
                {
                    _consecutiveFailures++;
                    if (_consecutiveFailures >= _consecutiveFailuresThreshold)
                    {
                        TripCircuitBreaker(); // 连续失败达到阈值,触发熔断器
                        throw new InvalidOperationException("连续失败次数达到阈值,熔断器已触发。");
                    }

                    retryCount++;
                }
            }
            catch (Exception ex)
            {
                _consecutiveFailures++;
                if (_consecutiveFailures >= _consecutiveFailuresThreshold)
                {
                    TripCircuitBreaker(); // 连续失败达到阈值,触发熔断器
                    throw new InvalidOperationException("连续失败次数达到阈值,熔断器已触发。");
                }

                retryCount++;
            }
        }

        throw new Exception($"重试 {_maxRetries} 次后仍然无法发送请求。");
    }

    private async Task<HttpClient> GetHttpClientAsync()
    {
        if (_circuitBreakerTripped)
        {
            var elapsedTime = DateTime.Now - _circuitBreakerTrippedTime;
            if (elapsedTime < _circuitBreakerTimeout)
            {
                throw new InvalidOperationException("熔断器已触发,请稍后重试。");
            }
            else
            {
                // 重置熔断器
                _circuitBreakerTripped = false;
            }
        }

        if (await _semaphore.WaitAsync(_timeout))
        {
            if (_httpClientPool.TryDequeue(out var httpClient))
            {
                return httpClient;
            }
        }

        throw new TimeoutException("获取 HttpClient 超时。");
    }

    public void ReturnHttpClient(HttpClient httpClient, bool success)
    {
        if (success)
        {
            _httpClientPool.Enqueue(httpClient);
            _semaphore.Release();
        }
        else
        {
            // 触发熔断器
            TripCircuitBreaker();

            httpClient.Dispose();
            _semaphore.Release();
        }
    }

    private void TripCircuitBreaker()
    {
        _circuitBreakerTripped = true;
        _circuitBreakerTrippedTime = DateTime.Now;
        _consecutiveFailures = 0;
    }

    public void Dispose()
    {
        foreach (var httpClient in _httpClientPool)
        {
            httpClient.Dispose();
        }

        _httpClientPool.Clear();
        _semaphore.Dispose();
    }
}

调用端
 文章来源地址https://www.toymoban.com/news/detail-741899.html

public class Program
{
    public static async Task Main()
    {
        // 创建 HttpClientPool
        var httpClientPool = new HttpClientPool(maxPoolSize: 10,
            timeout: TimeSpan.FromSeconds(5),
            maxRetries: 3,
            circuitBreakerTimeout: TimeSpan.FromMinutes(10),
            consecutiveFailuresThreshold: 5);
        try
        {
            var response = await httpClientPool.SendRequestWithRetries("https://api.example.com");
            var content = await response.Content.ReadAsStringAsync();
            Console.WriteLine(content);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"请求失败:{ex.Message}");
        }
    }
}

到了这里,关于.net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot--超时熔断器

    如果一个服务中有很多涉及需要服务间熔断的地方,就会出现N多下述代码: 1.N个fegnClient接口 2.N个降级结果类 feign调用接口上都要加上fallback降级类,只是想简单方便且不需要关心创建及返回结果,并且可以把hystrix的框架包装在中间件中,屏蔽调用逻辑,让开发者更加关注于

    2024年02月12日
    浏览(52)
  • 微服务springcloud 06.feign框架,配合ribbon 负载均衡和重试,配合hystrix 降级,监控和熔断测试

    feign是ribbon +hystrix 的整合 01.新建 sp09-feign 项目 第一步: 第二步:选择依赖: pom.xml 需要添加 sp01-commons 依赖: 第三步:修改sp09-feign项目的application.yml 第四步:sp09-feign的主程序添加 @EnableDiscoveryClient 和 @EnableFeignClients 02.feign 声明式客户端 第一步:声明三个代理接口 这里的

    2024年02月10日
    浏览(56)
  • HTTP调用:你考虑到超时、重试、并发了吗?

    今天,我们一起聊聊进行 HTTP 调用需要注意的超时、重试、并发等问题。 与执行本地方法不同,进行 HTTP 调用本质上是通过 HTTP 协议进行一次网络请求。网络请求必然有超时的可能性,因此我们必须考虑到这三点: 首先,框架设置的默认超时是否合理; 其次,考虑到网络的

    2024年02月11日
    浏览(38)
  • uniapp 出现连接服务器超时,点击屏幕重试

    可以从以下几个方面排查问题:    当 Uniapp 应用出现服务器超时的情况时,可以采取以下步骤进行排查: 1. 检查网络连接是否正常:首先需要检查网络连接是否正常,包括本地网络和服务器网络,确保网络连接稳定。 2. 检查服务器是否正常:需要检查服务器是否正常运行,

    2024年02月16日
    浏览(57)
  • Kafka消费异常处理策略及重试机制

    在使用Kafka进行消息传递时,消费者可能会遇到各种异常情况,例如网络故障、消息处理失败等。为了保证消息的可靠消费,我们需要实现一套有效的异常处理策略和重试机制。本文将介绍如何在Kafka消费过程中处理异常,并提供相应的源代码示例。 异常处理策略 在Kafka消费

    2024年02月04日
    浏览(44)
  • .NET Core HttpClient请求异常分析

    推送逻辑是在类库中使用HttpClient,所以没有使用HttpClientFactory,因此定义静态变量来使用HttpClient,而非每一个请求就实例化一个HttpClient, 接下来我们来详细分析项目示例代码并对其进行改进 若对接方仅使用HTTPS协议,无需验证证书,最好是忽略证书验证,否则有可能会引起

    2024年02月03日
    浏览(50)
  • 一个.Net强大的Excel控件,支持WinForm、WPF、Android【强烈推荐】

    推荐一个强大的电子表单控件,使用简单且功能强大。 这是一个开源的表格控制组件,支持Winform、WPF和Android平台,可以方便的加载、修改和导出Excel文件,支持数据格式、大纲、公式计算、图表、脚本执行等、还支持触摸滑动,可以方便地操作表格。 总的来说是一个可以快

    2024年02月07日
    浏览(54)
  • 【设计模式与范式:行为型】61 | 策略模式(下):如何实现一个支持给不同大小文件排序的小程序?

    上一节课,我们主要介绍了策略模式的原理和实现,以及如何利用策略模式来移除 if-else 或者 switch-case 分支判断逻辑。今天,我们结合“给文件排序”这样一个具体的例子,来详细讲一讲策略模式的设计意图和应用场景。 除此之外,在今天的讲解中,我还会通过一步一步地

    2024年02月10日
    浏览(42)
  • 在.NET Core使用 HttpClient 的正确方式

    前言 HttpClient 是 .NET Framework、.NET Core 或 .NET 5以上版本中的一个类,用于向 Web API 发送 HTTP 请求并接收响应。它提供了一些简单易用的方法,如 GET、POST、PUT 和 DELETE,可以很容易地构造和发送 HTTP 请求,并处理响应数据。它是我们比较常用的官方HTTP请求组件,那么你们都正确

    2023年04月12日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包