# EasyCore.Polly **Repository Path**: wzhy-0521/easy-core.-polly ## Basic Information - **Project Name**: EasyCore.Polly - **Description**: EasyCore.Polly - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 1 - **Created**: 2025-03-10 - **Last Updated**: 2026-07-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: EasyCore ## README # 🛡️ EasyCore.Polly > **EasyCore.Polly** 是面向 .NET 8 的生产级 Polly 封装。通过 `[PollyConfig]` 为接口方法声明重试、超时、熔断、舱壁(Bulkhead)、降级(Fallback),基于 Castle DynamicProxy 自动生效。

EasyCore Logo

![.NET](https://img.shields.io/badge/.NET-8.0-512BD4?logo=dotnet) ![C#](https://img.shields.io/badge/C%23-12-239120?logo=csharp) ![Polly](https://img.shields.io/badge/Polly-7.2.4-orange) ![Proxy](https://img.shields.io/badge/Castle-DynamicProxy-blueviolet) ![License](https://img.shields.io/badge/License-MIT-yellow) ![Version](https://img.shields.io/badge/Version-8.0.1-blue) --- ## 🌍 Language - **中文(当前文档)** - English: [README.en.md](https://github.com/RockyWang0521/EasyCore.Polly/blob/master/README.en.md) --- ## 📚 目录 ### 第一部分:总览与架构 - [1. 项目定位](#1--项目定位) - [2. 架构与调用链](#2--架构与调用链) - [3. 仓库结构](#3--仓库结构) ### 第二部分:快速上手 - [4. 安装](#4--安装) - [5. 三分钟快速开始](#5--三分钟快速开始) - [6. 特性与配置](#6--特性与配置) ### 第三部分:策略与生产 - [7. 策略组合顺序](#7--策略组合顺序) - [8. Demo 项目](#8--demo-项目) - [9. 生产清单](#9--生产清单) - [10. FAQ](#10--faq) - [11. License](#11--license) --- ## 1. 🎯 项目定位 EasyCore.Polly 解决「在 .NET 里用特性声明韧性策略,而不是到处手写 Wrap」的问题: | 痛点 | EasyCore.Polly 做法 | |---|---| | 到处手写 Polly Wrap | 方法上挂 `[PollyConfig]` | | 手动注册代理 | `EasyCorePolly` + 接口发现 | | 扫盘注册脆弱 | 生产推荐 `AddAssemblyFrom()` | | `Task` 降级无返回值 | 泛型策略正确返回降级结果 | | 库强制加 Console 日志 | 日志由宿主配置 | ### 1.1 设计原则 | 原则 | 说明 | |---|---| | **低摩擦接入** | 一个扩展方法 + 一个特性即可跑通 | | **接口代理** | Castle DynamicProxy,策略对调用方透明 | | **显式程序集** | 生产环境用 `AddAssemblyFrom()` | | **策略可组合** | Retry / Timeout / CB / Bulkhead / Fallback 同屏配置 | | **命名空间干净** | 文件夹归类,公开 API 统一 `EasyCore.Polly` | --- ## 2. 🏗️ 架构与调用链 ### 2.1 组件关系图 ![architecture-cn](https://raw.githubusercontent.com/RockyWang0521/EasyCore.Polly/master/docs/svg/architecture-cn.svg) ### 2.2 调用时序 ```text [IOrderClient] ──► Castle Interface Proxy │ ▼ PollyStandardInterceptor │ ▼ PolicyCache ──► PolicyFactory │ ▼ Fallback → Retry → Timeout → CircuitBreaker → Bulkhead │ ▼ OrderClient.Method() ``` --- ## 3. 📁 仓库结构 ```text EasyCore.Polly/ ├── src/EasyCore.Polly/ │ ├── Abstractions/ # Options、Attribute │ ├── Discovery/ # 程序集发现 │ ├── Hosting/ # DI 扩展入口 │ ├── Interception/ # Castle 拦截器 │ └── Policies/ # 策略工厂与缓存 ├── demo/ │ ├── PollyTest/ # 共享示例服务 │ ├── WebApp.EasyCorePolly/ # ASP.NET Core + Swagger │ └── WinFormsApp.EasyCorePolly/ # WinForms ├── tests/EasyCore.Polly.Tests/ ├── docs/svg/ # README 架构图 └── png/EasyCoreLogo.png ``` > 文件夹仅用于归类;公开命名空间统一为 `EasyCore.Polly`。 --- ## 4. 📦 安装 ```bash dotnet add package EasyCore.Polly ``` 需要 **.NET 8**。 --- ## 5. ⚡ 三分钟快速开始 ### 5.1 定义接口与实现 ```csharp using EasyCore.Polly; public interface IOrderClient { Task GetOrderAsync(string id); } public sealed class OrderClient : IOrderClient { [PollyConfig( MaxRetry = 3, RetryIntervalSeconds = 1, TimeOutSeconds = 5, IsEnableCircuitBreaker = true, ExceptionsAllowedBeforeBreaking = 5, SecondsOfBreak = 30, ServiceDegradation = nameof(GetOrderFallbackAsync))] public Task GetOrderAsync(string id) => throw new HttpRequestException("upstream down"); public Task GetOrderFallbackAsync() => Task.FromResult("cached-or-default"); } ``` > 必须通过**接口代理**生效。实现类名 `OrderClient` 对应接口 `IOrderClient`。 ### 5.2 注册服务 两种写法都可以: ```csharp // 省事:自动扫描候选程序集(Demo / 本地) builder.Services.EasyCorePolly(); // 生产推荐:显式指定程序集 builder.Services.EasyCorePolly(options => { options.AddAssemblyFrom(); }); ``` 从 DI 解析 `IOrderClient` 即可得到带策略的代理。 --- ## 6. ⚙️ 特性与配置 ### 6.1 `[PollyConfig]` 属性一览 | 属性 | 说明 | 默认 | 图标语义 | |---|---|---|---| | `RateLimit` | **Bulkhead** 最大并发(`0`=关闭)。**不是**每秒限流 | `0` | 🧱 | | `RateQueuing` | Bulkhead 最大排队数 | `0` | 📥 | | `MaxRetry` | 重试次数(`0`=关闭) | `0` | 🔁 | | `RetryIntervalSeconds` | 重试间隔(秒) | `1` | ⏱️ | | `IsEnableCircuitBreaker` | 是否启用熔断 | `false` | ⚡ | | `ExceptionsAllowedBeforeBreaking` | 熔断前允许失败次数 | `3` | 💥 | | `SecondsOfBreak` | 熔断打开时长(秒) | `5` | ⏸️ | | `TimeOutSeconds` | 超时秒数(`0`=关闭) | `0` | ⌛ | | `ServiceDegradation` | 同类型上的无参降级方法名 | `null` | 🩹 | ### 6.2 `EasyCorePollyOptions` | API | 说明 | |---|---| | `AddAssemblyFrom()` | 扫描包含 `T` 的程序集(**生产推荐**) | | `AddAssembly(Assembly)` | 扫描指定程序集 | | `Assemblies` | 已配置列表(为空则候选扫盘) | --- ## 7. 🧩 策略组合顺序 ### 7.1 可视化 Wrap ![policy-wrap-cn](https://raw.githubusercontent.com/RockyWang0521/EasyCore.Polly/master/docs/svg/policy-wrap-cn.svg) ### 7.2 执行顺序 执行顺序(**外 → 内**): ```text Fallback → Retry → Timeout → CircuitBreaker → Bulkhead → 业务方法 ``` 与 EasyCore.Polly 使用的 Polly `WrapAsync` 语义一致。 | 策略 | 作用 | 对应属性 | |---|---|---| | 🩹 Fallback | 最终失败时降级 | `ServiceDegradation` | | 🔁 Retry | 瞬时故障重试 | `MaxRetry` / `RetryIntervalSeconds` | | ⌛ Timeout | 防止长时间阻塞 | `TimeOutSeconds` | | ⚡ CircuitBreaker | 防止雪崩 | `IsEnableCircuitBreaker` 等 | | 🧱 Bulkhead | 限制并发隔离故障 | `RateLimit` / `RateQueuing` | --- ## 8. 🧪 Demo 项目 | 项目 | 说明 | 场景 | |---|---|---| | `demo/WebApp.EasyCorePolly` | ASP.NET Core + Swagger | Web API 联调 | | `demo/WinFormsApp.EasyCorePolly` | WinForms | 桌面端演示 | | `demo/PollyTest` | 共享 `[PollyConfig]` 示例 | 被上述 Demo 引用 | ```bash dotnet test tests/EasyCore.Polly.Tests dotnet run --project demo/WebApp.EasyCorePolly ``` --- ## 9. ✅ 生产清单 - [ ] 使用 `AddAssemblyFrom()`,不要依赖扫盘 - [ ] 通过接口暴露服务(`I{类名}`) - [ ] 在宿主配置日志(Console/文件/OTLP),库不再注入 Console - [ ] 按 SLA 调整熔断与超时 - [ ] `Task` 场景让降级方法返回有效值 - [ ] 非法 `[PollyConfig]` 会在首次执行时抛错 --- ## 10. ❓ FAQ **Q: 为什么必须用接口?** A: 策略通过 Castle **接口代理**注入。仅有实现类不会被代理。 **Q: `RateLimit` 是每秒限流吗?** A: 不是。对应 Polly **Bulkhead**(最大并发 + 可选队列)。见上方策略图。 **Q: 降级方法可以返回什么?** A: `Task`、`Task`,或同步 `T`(泛型方法)。必须无参且在同一类型上。 **Q: 和 Ocelot / 网关的关系?** A: EasyCore.Polly 是**进程内**韧性。网关管边缘流量,可按需组合。 **Q: 支持 Polly v8 吗?** A: 当前绑定 **Polly 7.2.x**,以保持特性模型稳定。v8 Pipeline 需单独迁移。 --- ## 11. 📄 License MIT ### 🤝 贡献 1. Fork 并创建特性分支 2. 在 `tests/EasyCore.Polly.Tests` 补充测试 3. 执行 `dotnet test` 与 `dotnet build EasyCore.Polly.sln` 4. 提交 Pull Request 欢迎 Issue / PR 🚀