.NET平台下的一个弹性和瞬态故障处理库 Polly

目录

Polly 的应用场景

Polly 的安装

Polly的主要策略及使用


Polly 是一个.NET弹性和瞬态故障处理库,它允许开发者以流畅和线程安全的方式表达重试(Retry)、断路器(Circuit Breaker)、超时(Timeout)、隔板隔离(Bulkhead Isolation)和回退策略(Fallback)等策略。非常适合用于构建容错能力更强的应用程序。

Polly 的应用场景

  • • 网络请求重试

  • • 第三方服务调用超时处理

  • • 服务降级

  • • 缓存实现以提高响应速度

Polly 的安装

可以通过 Nuget 包管理器安装 Polly:

Install-Package Polly

Polly的主要策略及使用

1、重试(Retry):当执行的方法发生异常时,可以按照指定的次数进行重试。Polly 允许你指定需要处理的异常类型,重试次数以及每次重试的回调函数。

using Polly;
 
//RetryForever 表示一直重试
//Retry 表示重试一次
//Retry(n) 表示重试n次
//WaitAndRetryAsync可实现等待100ms再试,还不行在等150ms再试
Policy polly = Policy.Handle<Exception>().Retry(3);
polly.Execute(() => {
    Console.WriteLine("开始");
    //DateTime.Now.Second%10!=0 重试错误的条件
    if (DateTime.Now.Second % 10 != 0)
    {
        Console.WriteLine("错误");
        throw new Exception("error");
    }
    Console.WriteLine("====完成=====");
});

2、 **断路器(Circuit Breaker)**:用于在连续的失败达到一定阈值后,停止执行操作,避免继续失败并允许服务有时间来恢复。

using Polly;

var circuitBreakerPolicy = Policy
    .Handle<HttpRequestException>()
    .CircuitBreaker(
        // 故障阈值:连续失败次数达到3次将触发断路器开启
        3,
        // 采样时长:30秒内的失败将被计入断路器状态
        TimeSpan.FromSeconds(30),
        // 断路器开启时执行的操作
        onBreak: (ex, breakDelay) =>
        {
            Console.WriteLine($"断路器由于 {ex.Message} 打开。" +
                              $"等待 {breakDelay.TotalSeconds} 秒后再次尝试。");
            // 可以在这里添加额外的操作,如记录日志、记录指标等。
        },
        // 可选:断路器重置时执行的操作
        onReset: () =>
        {
            Console.WriteLine("断路器已重置。");
        },
        // 可选:断路器半开启时执行的操作
        onHalfOpen: () =>
        {
            Console.WriteLine("断路器处于半开启状态。");
        });

// 使用断路器策略的示例代码
circuitBreakerPolicy.Execute(() =>
{
    var http=new HttpClient();
    // 可能会抛出 HttpRequestException 的代码
    var response = http.GetAsync("https://www.example.com/api/data").Result;
    response.EnsureSuccessStatusCode();
    var content = response.Content.ReadAsStringAsync().Result;
    Console.WriteLine($"收到的响应:{content}");
});

3、 超时(Timeout):用于监控任务执行的时长,如果超出指定时长则认为任务执行失败,不会继续等待结果。Polly 中关于超时的两个策略:一个是悲观策略(Pessimistic),一个是乐观策略(Optimistic)。其中,悲观策略超时后会直接抛异常,而乐观策略则不会,而只是触发CancellationTokenSource.Cancel函数,需要等待委托自行终止操作。一般情况下,我们都会用悲观策略。

https://www.cnblogs.com/Mamba8-24/p/17094636.html

 
using Polly.Timeout;
using Polly;
// 创建一个超时策略,设置超时时间为5秒
var timeoutPolicy = Policy.TimeoutAsync(5, TimeoutStrategy.Pessimistic);

try
{
    // 执行策略包裹的方法
    await timeoutPolicy.ExecuteAsync(async () =>
    {
        // 模拟一个耗时操作,延迟6秒
        Console.WriteLine("开始执行耗时操作...");
        await Task.Delay(6000);  // 使用异步等待
        Console.WriteLine("耗时操作完成。");
    });
}
catch (TimeoutRejectedException)
{
    // 处理超时异常
    Console.WriteLine("操作超时");
}

4、 回退(Fallback):当操作注定失败时,提供一个备用方案来替代失败的操作,从而挽救失败的操作。

var httpClient = new HttpClient();

// 定义一个回退策略,当操作失败时,返回一个默认值
var fallbackPolicy = Policy<string>
    .Handle<HttpRequestException>()
    .FallbackAsync(async (cancellationToken) =>
    {
        // 这里定义回退操作,返回默认值
        Console.WriteLine("Fallback action is executed.");
        return await Task.FromResult("Fallback response");
    });

try
{
    var response = await fallbackPolicy.ExecuteAsync(async () =>
    {
        var result = await httpClient.GetStringAsync("https://example.com");
        return result;
    });

    // 打印最终的响应结果
    Console.WriteLine($"Response: {response}");
}
catch (Exception ex)
{
    Console.WriteLine($"Request failed: {ex.Message}");
}

5、 隔板隔离策略(Bulkhead Isolation):用于限制并发操作数量的模式,以防止系统过载。这种策略将系统资源分隔成多个独立的部分(隔板),每个部分可以独立地处理请求,从而限制单个部分的资源消耗,保护整体系统的稳定性。

var httpClient = new HttpClient();

// 定义一个隔板隔离策略,限制并发操作数为5,队列长度为10
var bulkheadPolicy = Policy.BulkheadAsync<HttpResponseMessage>(
    maxParallelization: 5,
    maxQueuingActions: 10,
    onBulkheadRejectedAsync: async context =>
    {
        Console.WriteLine("Bulkhead isolation: Too many requests.");
        await Task.CompletedTask;
    });

var tasks = new Task<HttpResponseMessage>[15];

for (int i = 0; i < tasks.Length; i++)
{
    tasks[i] = bulkheadPolicy.ExecuteAsync(async () =>
    {
        var response = await httpClient.GetAsync("https://example.com");
        response.EnsureSuccessStatusCode();
        return response;
    });
}

try
{
    var responses = await Task.WhenAll(tasks);

    foreach (var response in responses)
    {
        Console.WriteLine($"Response: {response.StatusCode}");
    }
}
catch (Exception ex)
{
    Console.WriteLine($"Request failed: {ex.Message}");
}

6、缓存策略(Cache):对于数据更新周期长且频繁使用的数据,首次加载后缓存起来,后续直接从缓存中读取。

dotnet add package Polly.Caching.Memory

using Microsoft.Extensions.Caching.Memory;
using Polly;
using Polly.Caching.Memory;

var httpClient = new HttpClient();
var memoryCache = new MemoryCache(new MemoryCacheOptions());

// 定义一个缓存策略,缓存时间为60秒
var cachePolicy = Policy.CacheAsync<HttpResponseMessage>(
    new MemoryCacheProvider(memoryCache),
    TimeSpan.FromSeconds(60));

try
{
    // 第一次请求,将缓存结果
    var response1 = await cachePolicy.ExecuteAsync(async context =>
    {
        return await httpClient.GetAsync("https://example.com");
    }, new Context("cacheKey"));

    Console.WriteLine($"First request status code: {response1.StatusCode}");

    // 第二次请求,将从缓存中获取结果
    var response2 = await cachePolicy.ExecuteAsync(async context =>
    {
        return await httpClient.GetAsync("https://example.com");
    }, new Context("cacheKey"));

    Console.WriteLine($"Second request status code: {response2.StatusCode}");
}
catch (Exception ex)
{
    Console.WriteLine($"Request failed: {ex.Message}");
}

7、策略包装策略(Policy Wrap):不同的异常需要不同的策略,策略包装允许将不同的策略组合在一起,灵活应对不同的异常情况。

var httpClient = new HttpClient();

// 定义重试策略
var retryPolicy = Policy
    .Handle<HttpRequestException>()
    .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
        (exception, timeSpan, context) =>
        {
            Console.WriteLine($"Retrying due to: {exception.Message}");
        });

// 定义断路器策略
var circuitBreakerPolicy = Policy
    .Handle<HttpRequestException>()
    .CircuitBreakerAsync(2, TimeSpan.FromSeconds(30),
        onBreak: (exception, timespan) =>
        {
            Console.WriteLine("Circuit breaker opened");
        },
        onReset: () =>
        {
            Console.WriteLine("Circuit breaker closed");
        });

 
// 将策略包装起来
var policyWrap = Policy.WrapAsync(retryPolicy, circuitBreakerPolicy);

try
{
    var response = await policyWrap.ExecuteAsync(async () =>
    {
        var result = await httpClient.GetAsync("https://example.com");
        result.EnsureSuccessStatusCode();
        return result;
    });

    // 打印响应结果
    Console.WriteLine($"Response: {response.StatusCode}");
}
catch (Exception ex)
{
    Console.WriteLine($"Request failed: {ex.Message}");
}

引入地址 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值