将策略定义与执行分开时了解 Polly 策略的语义

Understanding the semantics of Polly policies when separating policy definition from execution

对于 Polly 我想在两个不同的语句中定义我的策略定义和该策略的执行,如:

// Policy definition
var policy = Policy
   .HandleResult<IRestResponse>(predicate)
   .Retry(2);

// Policy execution
policy.ExecuteAndCapture(() =>
{
    DoSomethingAndReturnAnIRestResponse();
};

我想这样做,这样我就可以更好地重用我的重试策略,例如用于依赖注入。

我试图了解在以这种方式拆分政策和执行时是否有任何注意事项,例如,是否有任何 "state"(由于缺少更好的术语)可能无法进行policy 从策略定义到执行的对象。

沿着这些思路,我注意到当我以上述方式使用 Polly 的 ExecuteAndCapture() 时,某些属性(与捕获最终 exception/outcome 相关的属性,与 ExecuteAndCapture() 相关的属性)未显示在 policy 对象上。根据文档 (here and here),完成如下策略后:

var policy = Policy
   .HandleResult<IRestResponse>(predicate)
   .Retry(2)
   .ExecuteAndCapture(() =>
    {
       DoSomethingAndReturnAnIRestResponse();
    });

...你应该回来:

PolicyResult.Outcome
PolicyResult.FinalException
PolicyResult.ExceptionType
PolicyResult.Result

这确实发生了,然后 ExecuteAndCapture() 与策略定义在同一个语句中。但是,当将策略定义与执行分开时,这些属性不可用。我天真地假设它们会出现在现有的 policy 对象上,但它们不会:

看来我需要创建一个新的变量赋值才能访问这些属性:

这里有什么问题吗?

不用担心。配置与其使用分开的策略,并将它们注入使用站点,是我们在生产中广泛使用的常见模式。

所有 Polly 策略都是线程安全的,可以同时跨多个独立调用站点使用。


两种 Polly 策略线程安全地跨调用维护内部状态,以执行其设计的功能。如果您在调用站点之间共享这些策略实例,这会产生特定的(预期的)效果。

CircuitBreaker / AdvancedCircuitBreaker

存在的理由是根据 success/fail 指标对通过该策略发出的呼叫进行计数并采取行动。每个单独的策略实例都在内部为自己维护此状态。

这样做的(预期)功能结果是,如果您在多个调用站点共享一个 CircuitBreakerPolicy 实例,那么这些多个调用站点将共享电路状态 as discussed here

  • 当您希望这些调用点共同中断时,在调用点之间共享相同的断路器策略实例 - 例如,它们具有共同的下游依赖性。
  • 当您希望调用站点具有独立的电路状态并独立中断时,请不要跨调用站点共享断路器实例。

Bulkhead

存在的理由是限制通过它发出的调用的并发性。每个 BulkheadPolicy 实例都在内部维护状态以对其进行跟踪。

这样做的(预期)功能结果是,当您在多个调用站点之间共享一个 BulkheadPolicy 实例时,这些调用站点将共享它们之间的隔板容量。

  • 当您希望调用站点在它们之间共享隔板容量时,在多个调用站点之间共享相同的 BulkheadPolicy 实例。
  • 当您希望多个调用站点具有独立的舱壁容量时,不要在多个调用站点之间共享同一个 BulkheadPolicy 实例。

没有其他类型的 Polly 策略在执行过程中维护策略实例中的内部状态。


.ExecuteAndCapture(...)

.ExecuteAndCapture(...) 调用的结果不在问题中 个案例中的 policy 个案例中。在这两种情况下(在一个语句中定义和执行;或分开),result of the .ExecuteAndCapture(...) call is a fresh PolicyResult 实例。

每次执行 returns 一个新的 PolicyResult 实例。 PolicyResult 永远不会作为状态存储在策略实例上(这会使策略不是线程安全的并且无法跨调用站点重用)。

将每个代码位置的var改为实际类型(PolicyPolicyResult),这样可能看得更清楚。