如何用Polly实现首次10秒、后续5秒重试且总时长3分钟的逻辑?
解决Polly实现SqlConnection差异化延迟重试及总时长限制问题
核心问题分析
- 异常被内部拦截:你的
reTryDB方法内部捕获了Exception但未重新抛出,导致Polly无法感知异常,重试逻辑永远不会触发。 - 策略拆分与组合错误:拆分两个重试策略并通过
Wrap组合的方式不符合需求,且Wrap顺序错误——Timeout策略应作为外层控制总时长。 - Handle条件冗余:
retryFirstTime中包含了DivideByZeroException,与SqlConnection重试需求无关,应剔除。
修正后的实现方案
步骤1:修复业务方法,确保异常能被Polly捕获
修改reTryDB方法,捕获异常后重新抛出,让Polly感知到错误:
public static void reTryDB(SqlConnection conn) { Console.WriteLine($"Open Sql con at {DateTime.Now.ToString("hh.mm.ss.ffffff")}"); try { conn.Open(); string selectCommand = "SELECT TOP 1 * FROM [dbo].[TAbleA]"; using var command = new SqlCommand(selectCommand, conn); using SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { Console.WriteLine(String.Format("{0}", reader[0])); } conn.Close(); } catch (Exception ex) { Console.WriteLine($"Encountered error: {ex.ToString()}"); throw; // 必须重新抛出,Polly才能触发重试 } }
步骤2:定义单一重试策略实现差异化延迟
通过WaitAndRetryForever的sleepDurationProvider参数,根据重试次数设置不同延迟:
// 首次重试延迟10秒,后续所有重试延迟5秒 Policy retryPolicy = Policy .Handle<SqlException>() // 仅针对SqlException触发重试 .Or<TimeoutException>() // 可选:如需处理超时异常可保留 .WaitAndRetryForever( sleepDurationProvider: retryAttempt => retryAttempt == 1 ? TimeSpan.FromSeconds(10) : TimeSpan.FromSeconds(5), onRetry: (exception, retryDelay, retryCount, context) => { Console.WriteLine($"Retry attempt {retryCount} - waiting {retryDelay.TotalSeconds}s before next try at {DateTime.Now.ToString("hh.mm.ss.ffffff")}"); } );
步骤3:定义总时长超时策略
设置3分钟的总超时,控制整个重试流程的最长时间:
// 总重试时长不超过3分钟 Policy timeoutPolicy = Policy.Timeout( TimeSpan.FromMinutes(3), TimeoutStrategy.Pessimistic, // 同步场景推荐使用Pessimistic策略 (context, timespan, task) => { Console.WriteLine($"Total retry duration exceeded {timespan.TotalMinutes} minutes, stopping retries."); } );
步骤4:正确组合策略
将Timeout策略作为外层,重试策略作为内层,确保总时长限制生效:
Policy combinedPolicy = Policy.Wrap(timeoutPolicy, retryPolicy);
步骤5:使用组合策略
combinedPolicy.Execute(() => reTryDB(conn));
关键说明
- 重试次数计数:
WaitAndRetryForever中的retryAttempt从1开始计数,第一次重试对应retryAttempt=1,以此类推。 - 策略组合逻辑:
Policy.Wrap(外层策略, 内层策略),外层的Timeout策略会包裹整个重试流程,确保总时长不超限。 - 异常传递要求:业务方法必须将异常抛出,Polly才能触发重试逻辑,内部捕获后不抛出会导致重试完全失效。
内容的提问来源于stack exchange,提问作者Mit Jacob
相关产品推荐
相关产品推荐

