使用Polly异步重试策略时重试前记录日志的正确方法
问题根因
WaitAndRetryAsync的onRetryAsync参数要求绑定的委托必须返回Task类型,你当前传入的lambda直接调用返回值为void的同步LogInfo方法,返回值不匹配委托签名,因此触发编译错误。另外原代码日志中引用的result.Result变量不在当前委托的参数列表中,属于隐藏的运行时错误。
正确实现方式
根据你使用的日志方法是同步还是异步,选对应写法即可:
场景1:使用同步日志方法(返回void)
直接在lambda中显式返回Task.CompletedTask即可匹配委托签名,不需要额外加async包装产生多余的性能开销:
var policy = Polly.Policy .Handle<SomeExceptionType>() .WaitAndRetryAsync( retryCount: this.maxRetryCount, sleepDurationProvider: (_, e, context) => { var waitTimeSpan = TimeSpan.FromSeconds(1); if (e != null && e is SomeExceptionType someException) { var retryAfterFromException = someException.Headers?.RetryAfter.Delta; if (retryAfterFromException > TimeSpan.Zero) { waitTimeSpan = retryAfterFromException.GetValueOrDefault(); } } return waitTimeSpan; }, onRetryAsync: (e, timeSpan, retryCount) => { // 修正原代码不存在的result变量,从异常对象取状态码 this.logger.LogInfo($"Request failed with {e.StatusCode}. Waiting {timeSpan} before next retry. Retry attempt {retryCount}"); return Task.CompletedTask; });
如果习惯用async语法,也可以写成async lambda,效果一致:
onRetryAsync: async (e, timeSpan, retryCount) => { this.logger.LogInfo($"Request failed with {e.StatusCode}. Waiting {timeSpan} before next retry. Retry attempt {retryCount}"); await Task.CompletedTask; }
场景2:使用异步日志方法(返回Task)
直接await异步日志方法即可,编译器会自动生成符合签名的Task返回值:
onRetryAsync: async (e, timeSpan, retryCount) => { await this.logger.LogInfoAsync($"Request failed with {e.StatusCode}. Waiting {timeSpan} before next retry. Retry attempt {retryCount}"); }
注意事项
- 禁止用
async void写法编写onRetryAsync的委托,会丢失异步执行上下文,导致异常无法被Polly捕获,甚至触发进程级崩溃。 - 若需要记录请求ID、业务标识等自定义上下文,可以使用带
Context参数的onRetryAsync重载,执行Policy时传入对应上下文数据即可。 - 仅当你通过
HandleResult<T>匹配返回值触发重试时,onRetry委托才会传入result参数,仅捕获异常的重试场景下,所有错误信息都需要从异常对象中提取。
内容的提问来源于stack exchange,提问作者Satashree Roy
相关产品推荐
相关产品推荐

