在将策略定义与执行分离时,了解Polly策略的语义

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

// Policy definition var policy = Policy .HandleResult(predicate) .Retry(2); // Policy execution policy.ExecuteAndCapture(() => { DoSomethingAndReturnAnIRestResponse(); }; 

我想这样做,所以我可以更好地重用我的重试策略,例如用于dependency injection。

我试图了解在以这种方式拆分策略和执行时是否有任何考虑因素,例如,如果存在任何可能未从策略定义到policy对象的“状态”(缺少更好的术语)执行。

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

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

……你应该回来:

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

确实发生这种情况,然后ExecuteAndCapture()与策略定义在同一语句中。 但是,在将策略定义与执行分离时,这些属性不可用。 我天真地认为他们会出现在现有的policy对象上,但他们没有:

在此处输入图像描述

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

带有结果的新政策变量

有什么顾虑吗?

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

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


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

CircuitBreaker / AdvancedCircuitBreaker

存在的理由是根据通过政策发出的呼叫的成功/失败指标来计算和行动。 每个单个策略实例都在内部为自己维护此状态。

这样的(预期)function结果是,如果您在多个呼叫站点中共享CircuitBreakerPolicy实例,那么这些多个呼叫站点将共享电路状态, 如此处所述 。

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

Bulkhead

存在的理由是限制通过它进行的呼叫的并发性。 每个单独的BulkheadPolicy实例都在内部维护状态以跟踪它。

这样做的(预期)function结果是,当您在呼叫站点之间共享BulkheadPolicy实例时,这些呼叫站点将共享它们之间的隔板容量。

  • 如果希望呼叫站点共享它们之间的隔板容量,请在多个呼叫站点之间共享相同的BulkheadPolicy实例。
  • 如果希望它们具有独立的隔板容量,请不要在多个呼叫站点之间共享同一个BulkheadPolicy实例。

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


.ExecuteAndCapture(...)

在问题的任何一种情况下, .ExecuteAndCapture(...)调用的结果都不在policy中。 在这两种情况下(在一个语句中定义和执行;或者分开) PolicyResult .ExecuteAndCapture(...)调用的结果是一个新的PolicyResult实例。

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

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