You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 06:28:25