.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();
    }
}

调用端
 

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}");
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/114321.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

逻辑(css3)_强制不换行

需求 如上图做一个跑马灯数据&#xff0c;时间、地点、姓名、提示文本字数都不是固定的。 逻辑思想 个人想法是给四个文本均设置宽度&#xff0c;不然会出现不能左对齐的现象。 此时四个文本均左对齐&#xff0c; 垂直排列样式也比较好看&#xff0c;但是出现一个缺点&#…

STM32-HAL库08-TIM的输出比较模式(输出PWM的另一种方式)

STM32-HAL库08-TIM的输出比较模式&#xff08;输出PWM的另一种方式&#xff09; 一、所用材料&#xff1a; STM32F103C6T6最小系统板 STM32CUBEMX&#xff08;HAL库软件&#xff09; MDK5 示波器或者逻辑分析仪 二、所学内容&#xff1a; 通过定时器TIM的输出比较模式得到预…

基于深度学习的视频多目标跟踪实现 计算机竞赛

文章目录 1 前言2 先上成果3 多目标跟踪的两种方法3.1 方法13.2 方法2 4 Tracking By Detecting的跟踪过程4.1 存在的问题4.2 基于轨迹预测的跟踪方式 5 训练代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的视频多目标跟踪实现 …

【设计模式】第11节:结构型模式之“装饰器模式”

一、简介 装饰器模式主要解决继承关系过于复杂的问题&#xff0c;通过组合来替代继承。它主要的作用是给原始类添加增强功能。这也是判断是否该用装饰器模式的一个重要的依据。除此之外&#xff0c;装饰器模式还有一个特点&#xff0c;那就是可以对原始类嵌套使用多个装饰器。…

开槌在即:陈可之油画|《我的星辰》

《我的星辰》 尺寸&#xff1a;46x46cm 陈可之2020年绘 “星辰大海&#xff0c;梦想自有梦想的力量&#xff0c;仰望在银河的想象&#xff0c;我们启航。”读着画名&#xff0c;凝视着画&#xff0c;脑海里回荡着《星辰大海》的旋律。油画《我的星辰》是陈可之先生“心宇宙”系…

AI开源 - LangChain UI 之 Flowise

原文&#xff1a;AI开源 - LangChain UI 之 Flowise 一、Flowise 简介 Flowise 是一个为 LangChain 设计的用户界面(UI)&#xff0c;使得使用 LangChain 变得更加容易&#xff08;低代码模式&#xff09;。 通过拖拽可视化的组件&#xff0c;组建工作流&#xff0c;就可以轻…

企业几种快速传输大文件的使用方法,你GET到了吗

在当今信息化时代&#xff0c;数据已经成为企业最重要的资产之一。大文件的传输在企业的日常工作中是一个常见需求&#xff0c;无论是用于内部协作还是与外部合作伙伴之间的数据交流&#xff0c;都需要高效、安全、稳定地传输大文件&#xff0c;以确保数据的完整性和及时性。本…

HarmonyOS鸿蒙原生应用开发设计- 隐私声明

HarmonyOS设计文档中&#xff0c;为大家提供了独特的隐私声明&#xff0c;开发者可以根据需要直接引用。 开发者直接使用官方提供的隐私声明内容&#xff0c;既可以符合HarmonyOS原生应用的开发上架运营规范&#xff0c;又可以防止使用别人的内容产生的侵权意外情况等&#xff…

DataCastle企业风险算法赛实战(进阶难度)

目录 一、数据读取及分析 1、数据读取 2、数据分析 二、数据挖掘 三、模型构建及评估 四、划重点 推荐相关文章 去年在DataCastle上参加了华录杯算法赛&#xff0c;初赛前10、进复赛就没打了。相比于之前文章 kaggle风控建模实战&#xff08;文末附链接&#xff09;&…

Windows11恢复组策略编辑器功能的方法

原因分析 日常工作学习中,对 Windows 计算机上的问题进行故障排除时,有些高级用户经常使用组策略编辑器轻松修复它。通过其分层结构,您可以快速调整应用于用户或计算机的设置。如果搜索结果中缺少组策略编辑器,则可能必须使用注册表编辑器作为疑难解答工具,这是一种更复杂…

【windows】添加共享打印机错误:0x000006ba

【问题描述】 添加共享打印机的时候&#xff0c;提示操作无法完成。 错误&#xff1a;0x000006ba。 【解决方法】 一、看下服务里 打印机服务Print Spooler是否正常启动&#xff1b; 二、打印机服务Print Spooler没有的话&#xff1b;&#xff08;开始–运行—services.msc 回…

vue3+ts封装图标选择组件

概要 讲解在vue3的项目中封装一个简单好用的图标选择组件。 效果 第一步&#xff0c;准备图标数据 数据太多&#xff0c;大家去项目中看。项目地址https://gitee.com/nideweixiaonuannuande/xt-admin-vue3 第二步&#xff0c;页面与样式编写 <template><div>…

【IDEA使用maven package时,出现依赖不存在以及无法从仓库获取本地依赖的问题】

Install Parent project C:\Users\lxh\.jdks\corretto-1.8.0_362\bin\java.exe -Dmaven.multiModuleProjectDirectoryD:\学习\projectFile\study\study_example_service "-Dmaven.homeD:\Program Files\JetBrains\IntelliJ IDEA2021\plugins\maven\lib\maven3" "…

Flink日志采集-ELK可视化实现

一、各组件版本 组件版本Flink1.16.1kafka2.0.0Logstash6.5.4Elasticseach6.3.1Kibana6.3.1 针对按照⽇志⽂件⼤⼩滚动⽣成⽂件的⽅式&#xff0c;可能因为某个错误的问题&#xff0c;需要看好多个⽇志⽂件&#xff0c;还有Flink on Yarn模式提交Flink任务&#xff0c;在任务执…

Linux基础环境开发工具的使用(yum,vim,gcc,g++)

Linux基础环境开发工具的使用[yum,vim,gcc,g] 一.yum1.yum的快速入门1.yum安装软件2.yum卸载软件 2.yum的生态环境1.操作系统的分化2.四个问题1.服务器是谁提供的呢?2.服务器上的软件是谁提供的呢?3.为什么要提供呢?4.yum是如何得知目标服务器的地址和下载链接呢?5.软件源 …

VMware打开centos黑屏解决方法汇总以及解决出现的bug(Centos7系统网络异常等)

VMware打开centos黑屏解决方法汇总 前言&#xff1a;一. VMware打开centos黑屏解决方法汇总一 .情况情况一&#xff1a;情况二情况三 二. 解决方法最简单的方法&#xff1a;一. 以管理员权限在命令行执行1. 管理员身份运行cmd2. 输入“netsh winsock reset”,回车3. 重启电脑即…

Python条件判断的运用

问题 在生活中&#xff0c;我们可以通过判断条件是否成立&#xff0c;来决定执行哪个分支。选择语句有多种形式&#xff1a;if语句&#xff0c;if-else语句&#xff0c;if-elif-else语句等。 Python使用if条件判断语句来实现条件判断时&#xff0c;可以在多个循环中实现对问题的…

Linux-----nginx的简介,nginx搭载负载均衡以及nginx部署前后端分离项目

目录 nginx的简介 是什么 nginx的特点以及功能 Nginx负载均衡 下载 安装 负载均衡 nginx的简介 是什么 Nginx是一个高性能的开源Web服务器和反向代理服务器。它的设计目标是为了解决C10k问题&#xff0c;即在同一时间内支持上万个并发连接。 Nginx采用事件驱动的异…

【云原生-K8s】Kubernetes安全组件CIS基准kube-beach安装及使用

基础介绍kube-beach介绍kube-beach 下载百度网盘下载wget下载 kube-beach安装kube-beach使用基础参数配置信息解读示例结果说明 基础介绍 为了保证集群以及容器应用的安全&#xff0c;Kubernetes 提供了多种安全机制&#xff0c;限制容器的行为&#xff0c;减少容器和集群的攻…
最新文章