当前位置: 首页 > news >正文

[Polly智能维护网络] 弹性管道 | 弹性管道构建器 | new | Add | .Build()

第2章:弹性管道

在第1章中,我们学习了**弹性策略**——诸如"失败时重试"或"超时停止"等独立的"安全规则"。这些策略本身很强大,但如果我们需要对同一操作应用多个安全规则呢

想象我们正在拨打一个重要电话:

  • 首先,我们希望确保不会无限等待对方接听(超时规则)
  • 如果线路忙,我们想再试几次(重试规则)
  • 如果持续听到忙音,可能希望暂停拨打以免打扰对方或自己(断路器规则)

我们不会随机应用这些规则,而是有特定计划:先检查超时,然后重试,最后触发断路器。这种组合和顺序至关重要。

这正是Polly中弹性管道的作用。

什么是弹性管道?

弹性管道视为代码的终极"安全卫士"或完整"战术手册"。

当代码需要执行高风险操作(如通过互联网与其他服务通信)时,我们将任务交给这个安全卫士。

管道会按照特定顺序应用所有安全规则(配置的**弹性策略**对象),确保操作尽可能可靠。

它是Polly的核心部分,实际执行代码的同时用所有弹性逻辑包裹代码。

弹性管道本质上是由**弹性策略**对象按特定顺序组成的链条。

每个策略像包裹核心操作的一层,在将操作传递给链中下一个策略或最终实际代码前应用其规则。

为什么需要管道?

我们需要管道来实现:

  1. 组合策略:对单个操作应用多个"安全规则"
  2. 排序策略:确保安全规则按正确顺序应用。例如通常希望先TimeoutRetry,避免重试已超时的操作
  3. 集中执行:提供单一入口点自动运行带有所有弹性逻辑的代码

构建和使用弹性管道

要使用弹性管道,首先需要通过添加所需的**弹性策略**对象来构建它。

Polly提供了专用工具弹性管道构建器(下章详述),帮助我们轻松创建管道。

让我们创建一个先Timeout操作再Retry失败操作(可能因网络故障)的管道:

using Polly;
using Polly.Retry;
using Polly.Timeout;// 1. 创建弹性管道构建器
ResiliencePipeline pipeline = new ResiliencePipelineBuilder()// 2. 按应用顺序添加策略(最外层先添加)// 这里:超时(外层)-> 重试(内层)-> 实际代码.AddTimeout(TimeSpan.FromSeconds(2)) // 操作超过2秒则停止.AddRetry(new RetryStrategyOptions{MaxRetryAttempts = 2, // 最多重试2次Delay = TimeSpan.FromSeconds(0.5) // 重试间隔0.5秒}).Build(); // 3. 构建管道!

这里发生了什么?

  • 使用new ResiliencePipelineBuilder()开始构建管道
  • .AddTimeout(TimeSpan.FromSeconds(2))添加超时策略,作为最外层。如果整个操作(包括所有重试)超过2秒将被停止
  • .AddRetry(...)添加重试策略,作为内层,紧邻实际代码。如果代码失败,重试策略将介入
  • .Build()完成管道构建,创建可立即使用的ResiliencePipeline对象

现在通过这个管道执行一些不可靠代码:

// 此变量帮助模拟偶发故障
int attemptCount = 0;try
{await pipeline.ExecuteAsync(async token =>{attemptCount++;Console.WriteLine($"尝试 {attemptCount}: 调用外部服务...");if (attemptCount < 2){// 模拟瞬时故障(如网络故障)throw new HttpRequestException("服务不可用!");}// 模拟第三次尝试成功但缓慢的操作await Task.Delay(TimeSpan.FromSeconds(1), token);Console.WriteLine("尝试成功!");}, CancellationToken.None);Console.WriteLine("操作成功完成!");
}
catch (Exception ex)
{Console.WriteLine($"操作完全失败: {ex.Message}");
}

运行时会发生什么?

  1. 尝试1pipeline调用代码。attemptCount为1,抛出HttpRequestException
  2. Retry策略捕获异常。因MaxRetryAttempts为2,等待0.5秒后调度重试
  3. 尝试2pipeline(具体是Retry策略)再次调用代码。attemptCount为2,再次抛出HttpRequestException
  4. Retry策略再次捕获。还剩一次重试机会,等待0.5秒后调度重试
  5. 尝试3pipeline最后一次调用代码。attemptCount为3。此次无异常,执行Task.Delay(1)
  6. Timeout策略从尝试1开始运行的计时器确认整个过程(尝试1+0.5秒延迟+尝试2+0.5秒延迟+尝试3+1秒延迟)在2秒限制内完成
  7. 操作成功完成,显示"操作成功完成!"

如果第三次尝试的Task.Delay更长(如5秒),Timeout策略最终会介入并抛出TimeoutRejectedException,证明两个策略按定义顺序协同工作。

弹性管道内部工作原理

弹性管道通过为操作创建分层"洋葱"或"责任链"工作

当通过管道执行时,请求从最外层到最内层逐个通过策略。每个策略在实际代码周围添加其逻辑。

以下是操作通过含超时重试策略管道的简化流程:

在这里插入图片描述

在Polly源码中,ResiliencePipelineBuilder通过内部链接每个**弹性策略**的ExecuteCore方法构建此链条。调用.AddStrategy(...)时,它在先前添加的策略(或实际代码)周围添加新"包装层"。

参考samples/Intro/Program.cs创建组合管道的方式:

using Polly;
using Polly.Retry;
using Polly.Timeout;ResiliencePipeline pipeline = new ResiliencePipelineBuilder()// 先添加=最外层策略.AddRetry(new RetryStrategyOptions { /* ...选项... */ })// 后添加=内层策略.AddTimeout(new TimeoutStrategyOptions { /* ...选项... */ }).Build();

虽然代码中AddRetry出现在AddTimeout前,此示例与之前不同,展示策略顺序可配置。

  • ResiliencePipelineBuilder的经验法则是:最先Add的策略是最外层最后Add的策略是最内层,最接近实际代码。

  • 构建器将它们链式连接,当调用ExecuteAsync时,调用先通过最外层策略,然后是下一个,依此类推,直到实际操作。

Polly的ResiliencePipeline及其构建器管理此执行链,确保所有配置的"安全规则"正确有序应用。

结论

本章我们理解了弹性管道是Polly的核心组件,用于按特定顺序应用多个**弹性策略**对象执行代码。

它像"安全卫士"通过链式组合TimeoutRetry等策略确保操作可靠。

既然知道弹性管道是什么及为何重要,我们如何更详细地创建和配置这些强大管道呢?

这正是下章要探讨的:弹性管道构建器。


第3章:弹性管道构建器

在第2章中,我们学习了**弹性管道**。我们发现它就像一个"安全卫士",按照特定顺序应用多个"安全规则"(弹性策略对象)来使我们的代码更健壮。

但如何创建这个强大的安全卫士呢?是手动组装它的各个部分吗?这听起来很复杂,特别是当有很多规则时!

什么是弹性管道构建器?

想象我们想构建一个具有特定功能的定制"安全卫士"。

我们不会随便抓一堆工具就开始敲打,而是会聘请一位架构师设计师,他懂得如何将不同功能组合成一个完整可用的系统。

在Polly中,弹性管道构建器正是这样的架构师!它是一个特殊工具,帮助我们设计和*构建**弹性管道**

我们不需要直接创建复杂的管道,而是使用构建器逐步指定哪些"安全规则"(或[弹性策略]应该成为它的一部分。完成指定后,构建器会为我们构造出完整、可直接使用的管道。

它解决了将多个弹性策略对象轻松组合并排序成单一、连贯的**弹性管道**的问题。

如何使用弹性管道构建器

使用构建器就像遵循食谱:

  1. 开始设计:创建一个新的ResiliencePipelineBuilder对象。这就像获得一张空白蓝图。
  2. 添加规则(策略):然后逐个添加所需的弹性策略对象。每个Add方法(如AddTimeoutAddRetry)都会在蓝图中添加一个新的安全规则。
  3. 完成设计:添加完所有规则后,调用.Build()方法。这会告诉构建器根据蓝图构造最终的**弹性管道**对象。

让我们看看实际操作:

using Polly;
using Polly.Timeout; // 用于AddTimeout
using Polly.Retry;  // 用于AddRetry// 1. 开始设计"安全卫士"(弹性管道)
ResiliencePipeline pipeline = new ResiliencePipelineBuilder()// 2. 添加规则,最外层先添加// 规则1:整体超时(外层).AddTimeout(TimeSpan.FromSeconds(5))// 规则2:重试(内层),如果第一次尝试失败.AddRetry(new RetryStrategyOptions { MaxRetryAttempts = 2 })// 3. 完成设计,构建安全卫士!.Build();// 现在有了一个可立即使用的'pipeline'对象,
// 就像我们在第2章中做的那样
Console.WriteLine("弹性管道设计并构建完成!");

这段代码发生了什么?

  • new ResiliencePipelineBuilder():我们创建构建器实例。可以想象为打开安全卫士的设计软件。
  • .AddTimeout(TimeSpan.FromSeconds(5)):告诉构建器"首先添加一个规则,如果操作超过5秒就停止"。这成为安全卫士的最外层
  • .AddRetry(new RetryStrategyOptions { MaxRetryAttempts = 2 }):接着告诉构建器"然后添加一个规则,如果操作失败最多重试2次"。这成为内层,更接近实际代码。
  • .Build():最后告诉构建器"好了,所有规则都已就位,现在把它们组合起来,给我完整的**弹性管道**对象"

使用构建器Add策略的顺序非常重要:

第一个添加的策略将成为管道的最外层,最后一个添加的策略将成为最内层,最接近实际代码。

弹性管道构建器的内部工作原理

ResiliencePipelineBuilder的工作方式像一条装配线。调用Add方法时,它不会立即创建策略,而是收集每个弹性策略的"蓝图"或"指令"。

当最终调用.Build()时,构建器获取所有这些指令,并开始按正确顺序连接策略,创建我们在第2章讨论的分层"洋葱"结构。链中的每个策略都被赋予对"下一个"策略或实际代码的引用,形成完整的执行路径。

以下是构建器如何组合这些部分的简化视图:

在这里插入图片描述

如你所见,构建器收集设计选择,然后在Build()步骤中,通过链接策略对象构造实际可用的ResiliencePipeline

在幕后,我们使用的AddTimeoutAddRetry和其他Add方法实际上是"扩展方法"。这些方法只是调用构建器上一个更通用的方法AddStrategyAddStrategy方法接受一段特殊代码(“工厂委托”),告诉构建器在.Build()管道时如何创建特定的弹性策略。

我们甚至可以看到Polly自己的内部逻辑如何使用这种模式。例如,添加自定义策略时,我们会使用AddStrategy

using Polly;public static class CustomBuilderExtensions
{// 这是一个简化示例,展示如何用核心'AddStrategy'方法// 实现'AddMyCustomStrategy'public static ResiliencePipelineBuilder AddMyCustomStrategy(this ResiliencePipelineBuilder builder){// 关键是使用'AddStrategy'// 'context'提供有用信息,如遥测,// 策略可能需要这些信息return builder.AddStrategy(context =>{// 这是构建器在调用.Build()时// 实际创建策略对象的地方Console.WriteLine("创建MyCustomStrategy...");return new MyCustomStrategy();});}
}// 然后可以这样使用:
// var pipeline = new ResiliencePipelineBuilder().AddMyCustomStrategy().Build();

这表明ResiliencePipelineBuilder提供了一种灵活的方式,可以将任何类型的弹性策略添加到管道中,无论是内置的还是自定义的。

结论

弹性管道构建器是我们在Polly中构建强大可靠的**弹性管道**对象的重要工具。

它作为架构师,让我们能够轻松地以正确顺序指定和组合各种"安全规则"(弹性策略对象),而无需手动链接它们。

我们已经学会如何使用new ResiliencePipelineBuilder()启动构建器,Add策略,以及.Build()最终管道

既然知道如何添加策略,我们可能会想了解配置每个独立策略的所有不同方式。这正是我们下一章要探讨的内容:弹性策略选项。

http://www.dtcms.com/a/338463.html

相关文章:

  • PIX2SEQ: A LANGUAGE MODELING FRAMEWORK FOR OBJECT DETECTION
  • MongoDB从入门到精通:
  • 【LeetCode】17. 电话号码的字母组合
  • SpreadJS 协同服务器 MongoDB 数据库适配支持
  • [系统架构设计师]云原生架构设计理论与实践(十四)
  • flink+clinkhouse安装部署
  • 【数据结构】二叉树-堆(深入学习 )
  • Flink原理与实践 · 第三章总结
  • Jenkins项目发布基础
  • 代码随想录算法训练营四十六天|图论part04
  • CSS封装大屏自定义组件(标签线)
  • 在python中等号左边的都是对象,在matlab中等号a = 3+2 a就是个变量
  • 关系型数据库与非关系型数据库
  • 用户认证技术
  • 【笔记】扩散模型(一一):Stable Diffusion XL 理论与实现
  • 力扣hot100:盛最多水的容器:双指针法高效求解最大容量问题(11)
  • [NSSCTF 2022 Spring Recruit]rrrsssaaa
  • 94、23种设计模式之工厂方法模式(3/23)
  • 用户认证技术和应用控制技术总结
  • 接口和抽象类的区别(面试回答)
  • leetcode43. 字符串相乘
  • 遗传算法求解冷链路径优化问题matlab代码
  • [ Spring 框架 ] 框架搭建和属性赋值
  • android 实现表格效果
  • 《彩色终端》诗解——ANSI 艺术解(DeepSeek)
  • shell脚本第一阶段
  • Image-to-Music API 接入文档(图片生成音乐)
  • 【新手易混】find 命令中 -perm 选项的知识点
  • ANSI终端色彩控制知识散播(I):语法封装(Python)——《彩色终端》诗评
  • JavaScript 性能优化实战技术指南