商城首页欢迎来到中国正版软件门户

您的位置:首页 >C#用Polly处理短暂数据库网络故障

C#用Polly处理短暂数据库网络故障

  发布于2026-01-29 阅读(0)

扫一扫,手机访问

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

c# 如何用Polly处理短暂的数据库或网络故障

什么时候该用 Polly 重试而不是直接抛异常

数据库连接超时、网络抖动、SQL Server 的 SqlException 错误号 1205(死锁)、40613(Azure 数据库暂时不可用)这类瞬态故障,适合用 Polly 的重试策略。它不是用来掩盖逻辑错误或永久性失败(比如 SQL 语法错、主键冲突),而是给系统留出几秒喘息时间,等资源恢复。

关键判断点:错误是否可预期、短暂、大概率重试成功。如果不是,加 Polly 只会让响应更慢、日志更乱。

RetryAsync 处理常见瞬态异常

最常用的是按异常类型重试,比如对 SqlExceptionHttpRequestException 单独建策略。注意别笼统捕获 Exception,否则会把 NullReferenceException 也重试,毫无意义。

  • 推荐只重试明确已知的瞬态错误码,比如 SqlException.Number 是 1205、40613、10928
  • HTTP 请求建议配合 HttpResponseMessage.IsSuccessStatusCode == false + 状态码 429、503、504 判断
  • 默认最多重试 3 次,间隔用指数退避(ExponentialBackoff),避免雪崩式重试
var retryPolicy = Policy
    .Handle<SqlException>(ex => new[] { 1205, 40613, 10928 }.Contains(ex.Number))
    .Or<HttpRequestException>()
    .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<IDataApiClient>()
    .AddPolicyHandler(Policy
        .HandleResult<HttpResponseMessage>(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 把重试包进超时里

瞬态故障处理真正难的不是写几行重试代码,而是确认哪部分状态可安全重放、哪部分必须幂等、哪部分根本不能重试。

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注