Polly重试适用于数据库连接超时、网络抖动及SQL Server错误1205/40613等瞬态故障,而非逻辑错误;应按明确异常类型和错误码配置指数退避重试,并结合超时策略与状态管理。

什么时候该用 Polly 重试而不是直接抛异常
数据库连接超时、网络抖动、SQL Server 的 SqlException 错误号 1205(死锁)、40613(Azure 数据库暂时不可用)这类瞬态故障,适合用 Polly 的重试策略。它不是用来掩盖逻辑错误或永久性失败(比如 SQL 语法错、主键冲突),而是给系统留出几秒喘息时间,等资源恢复。
关键判断点:错误是否可预期、短暂、大概率重试成功。如果不是,加 Polly 只会让响应更慢、日志更乱。
用 RetryAsync 处理常见瞬态异常
最常用的是按异常类型重试,比如对 SqlException 和 HttpRequestException 单独建策略。注意别笼统捕获 Exception,否则会把 NullReferenceException 也重试,毫无意义。
- 推荐只重试明确已知的瞬态错误码,比如
SqlException.Number是 1205、40613、10928 - HTTP 请求建议配合
HttpResponseMessage.IsSuccessStatusCode == false+ 状态码 429、503、504 判断 - 默认最多重试 3 次,间隔用指数退避(
ExponentialBackoff),避免雪崩式重试
var retryPolicy = Policy
.Handle(ex => new[] { 1205, 40613, 10928 }.Contains(ex.Number))
.Or()
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: (retryAttempt) => TimeSpan.FromMilliseconds(Math.Pow(2, retryAttempt) * 100)); 如何把 Polly 策略注入到 DbContext 或 HttpClient
不要在每个 SaveChangesAsync 调用里手写 retryPolicy.ExecuteAsync(...),容易漏、难测、耦合重。正确做法是封装一层执行器,或利用 DI 注入策略实例。
- 对
HttpClient:用AddHttpClient+ConfigurePrimaryHttpMessageHandler不够,得用AddPolicyHandler链式注册 - 对 EF Core:不能直接包装
DbContext,但可以包装仓储方法,例如IRepository.SaveChangesAsync()内部调用retryPolicy.ExecuteAsync(() => context.SaveChangesAsync()) - 务必设置
PolicyRegistry全局管理策略,避免重复创建(Polly 策略不是轻量对象)
services.AddHttpClient() .AddPolicyHandler(Policy .HandleResult (r => !r.IsSuccessStatusCode && new[] { 429, 503, 504 }.Contains(r.StatusCode.GetHashCode())) .WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(200)));
为什么重试后还失败?三个最容易被忽略的点
重试本身不保证成功,很多问题藏在策略之外:
-
DbContext是 Scoped 生命周期,重试时如果上下文已追踪了脏数据,第二次SaveChangesAsync可能因并发冲突或状态异常直接炸掉——必须确保每次重试用的是干净状态,或启用AsNoTracking查询 - HTTP 请求体如果是流(如
StreamContent),重试时流可能已读完,导致后续请求发空体;改用StringContent或手动Seek(0) - 没设
Timeout策略兜底,单次重试耗时太久,整体请求卡死;建议组合Policy.WrapAsync把重试包进超时里
瞬态故障处理真正难的不是写几行重试代码,而是确认哪部分状态可安全重放、哪部分必须幂等、哪部分根本不能重试。










