如何在Polly.Core中使用新弹性策略实现带自定义动作的回退策略?
关于Polly.Core中实现自定义动作回退的正确方式
我有一个旧版Polly策略,支持回退到自定义动作,代码如下:
// 还有其他重载,包括同步无返回值的版本 // 因为部分旧服务还没异步化,所以需要这个方法 public void RetryWithPolicy(Action action) { var policy = Policy.Handle<BrokenCircuitException>() .Fallback(_ => action()) .Wrap(someCircuitBreakerPolicy) .Wrap(someWaitAndRetryPolicy); policy.Execute(action); }
我找不到在Polly.Core中用新弹性策略实现该逻辑的正确方法。考虑过用对冲策略允许重新执行回调,但看回退策略时找不到执行回调的途径。
更新
可能之前表述不清,不确定是不是误解了策略包装和管道弹性策略的模式。旧版里可以创建包含回退、熔断、重试的策略并执行;新版用管道构建器创建单管道,但不知道怎么加回退逻辑。曾尝试过以下实现,但行不通:
public void RetryWithStrategy(Action action) { var pipeline = _myPollyRegistry.GetPipeline("pipeline"); // 查了文档但还是没找到让管道回退到action()的方法,这么写不行 pipeline.Execute(_ => action(), CancellationToken.None, action()); // 或者是不是可以把action()传入上下文,让已构建的管道能回退到它? }
目前只能用以下辅助方法作为临时方案:
public void RetryWithStrategy(Action action) { try { _pipeline.Execute(_ => action(), CancellationToken.None); } catch (BrokenCircuitException) { // 熔断时做最后一次尝试,但不遵循重试策略的次数限制 action(); } }
现寻求在Polly.Core新弹性策略中实现带自定义动作回退的正确方法。
正确实现方式
在Polly.Core中,回退逻辑需要在管道构建阶段配置,而非执行阶段动态传入。以下是两种符合需求的实现方案:
方案1:通过上下文传递动态回退动作(适合复用管道场景)
如果管道需要复用,但每次调用的回退动作不同,可以借助ResilienceContext的属性传递动作:
// 提前构建可复用的管道 var pipeline = new ResiliencePipelineBuilder() // 先添加回退策略,注意Polly.Core的Wrap顺序和旧版相反 .AddFallback(new FallbackStrategyOptions { ShouldHandle = new PredicateBuilder().Handle<BrokenCircuitException>(), FallbackAction = args => { // 从上下文取出预先存入的回退动作 if (args.Context.Properties.TryGetValue("FallbackAction", out var actionObj) && actionObj is Action action) { action(); } return default; } }) .Wrap(_someCircuitBreakerStrategy) // 包裹熔断策略 .Wrap(_someWaitAndRetryStrategy) // 包裹重试策略 .Build();
执行时传入回退动作:
public void RetryWithStrategy(Action action) { var context = ResilienceContextPool.Shared.Get(); try { // 将回退动作存入上下文 context.Properties.Set("FallbackAction", action); pipeline.Execute(_ => action(), context); } finally { // 归还上下文到对象池,避免内存泄漏 ResilienceContextPool.Shared.Return(context); } }
方案2:动态构建管道(贴近旧版逻辑)
如果每次调用的回退动作都不同,且对性能要求不高,可以每次调用时动态构建管道:
public void RetryWithStrategy(Action action) { var pipeline = new ResiliencePipelineBuilder() .AddRetry(_someWaitAndRetryOptions) // 先执行重试 .AddCircuitBreaker(_someCircuitBreakerOptions) // 再执行熔断 .AddFallback(new FallbackStrategyOptions { ShouldHandle = new PredicateBuilder().Handle<BrokenCircuitException>(), FallbackAction = _ => { action(); // 直接执行自定义回退动作 return default; } }) .Build(); pipeline.Execute(_ => action()); }
关键注意点
- 策略顺序差异:Polly.Core的策略执行顺序和旧版相反。旧版
Fallback.Wrap(CircuitBreaker).Wrap(Retry)的执行顺序是Retry → CircuitBreaker → Fallback;而Polly.Core中AddFallback().Wrap(CircuitBreaker).Wrap(Retry)的执行顺序是Fallback → CircuitBreaker → Retry,需要根据业务逻辑调整顺序,确保回退是最后触发的兜底逻辑。
内容的提问来源于stack exchange,提问作者SamIAm
相关产品推荐
相关产品推荐

