将策略定义与执行分开时了解 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
改为实际类型(Policy
或PolicyResult
),这样可能看得更清楚。
对于 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
改为实际类型(Policy
或PolicyResult
),这样可能看得更清楚。