# 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 自动生效。






---
## 🌍 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 组件关系图

### 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

### 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 🚀