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(){// 创建 HttpClientPoolvar 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}");}}
}