我有以下政策:
var sharedBulkhead = Policy.BulkheadAsync(
maxParallelization: maxParallelizations,
maxQueuingActions: maxQueuingActions,
onBulkheadRejectedAsync: (context) =>
{
Log.Info($"Bulk head rejected => Policy Wrap: {context.PolicyWrapKey}, Policy: {context.PolicyKey}, Endpoint: {context.OperationKey}");
return TaskHelper.EmptyTask;
}
);
var retryPolicy = Policy.Handle<HttpRequestException>()
.Or<BrokenCircuitException>().WaitAndRetryAsync(
retryCount: maxRetryCount,
sleepDurationProvider: attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)),
onRetryAsync: (exception, calculatedWaitDuration, retryCount, context) =>
{
Log.Error($"Retry => Count: {retryCount}, Wait duration: {calculatedWaitDuration}, Policy Wrap: {context.PolicyWrapKey}, Policy: {context.PolicyKey}, Endpoint: {context.OperationKey}, Exception: {exception}.");
return TaskHelper.EmptyTask;
});
var circuitBreaker = Policy.Handle<Exception>(e => (e is HttpRequestException)).CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: maxExceptionsBeforeBreaking,
durationOfBreak: TimeSpan.FromSeconds(circuitBreakDurationSeconds),
onBreak: (exception, timespan, context) =>
{
Log.Error($"Circuit broken => Policy Wrap: {context.PolicyWrapKey}, Policy: {context.PolicyKey}, Endpoint: {context.OperationKey}, Exception: {exception}");
},
onReset: (context) =>
{
Log.Info($"Circuit reset => Policy Wrap: {context.PolicyWrapKey}, Policy: {context.PolicyKey}, Endpoint: {context.OperationKey}");
}
);
var fallbackForCircuitBreaker = Policy<bool>
.Handle<BrokenCircuitException>()
.FallbackAsync(
fallbackValue: false,
onFallbackAsync: (b, context) =>
{
Log.Error($"Operation attempted on broken circuit => Policy Wrap: {context.PolicyWrapKey}, Policy: {context.PolicyKey}, Endpoint: {context.OperationKey}");
return TaskHelper.EmptyTask;
}
);
var fallbackForAnyException = Policy<bool>
.Handle<Exception>()
.FallbackAsync(
fallbackAction: (ct, context) => { return Task.FromResult(false); },
onFallbackAsync: (e, context) =>
{
Log.Error($"An unexpected error occured => Policy Wrap: {context.PolicyWrapKey}, Policy: {context.PolicyKey}, Endpoint: {context.OperationKey}");
return TaskHelper.EmptyTask;
}
);
var resilienceStrategy = Policy.WrapAsync(retryPolicy, circuitBreaker, sharedBulkhead);
var policyWrap = fallbackForAnyException.WrapAsync(fallbackForCircuitBreaker.WrapAsync(resilienceStrategy));
现在,fallbackForCircuitBreaker
仅在所有重试均失败且上一次重试失败并BrokenCircuitException
时调用。为了使fallbackForCircuitBreaker
每次在断路时重试都被调用,应该进行哪些更改?
此外,我正在使用sharedBulkHead
,它是服务中的实例字段,并在构造函数中初始化。这是一个好习惯吗?理想情况下,在onBulkheadRejectedAsync
上应该做什么?我可以修改重试策略来处理批量头拒绝吗?
答案 0 :(得分:0)
现在,仅当所有重试均失败且最后一次重试失败并带有BrokenCircuitException时,才调用fallbackForCircuitBreaker。为了使每次在断路电路上重试时调用fallbackForCircuitBreaker,应该进行哪些更改?
请参见PolicyWrap documentation,尤其是diagrams and description of operation。 PolicyWrap中的策略就像调用周围的一系列嵌套中间件一样:
因此,要使每次尝试调用fallbackForCircuitBreaker
(相当于)fallbackForCircuitBreaker
,请将其移到重试策略中。
但是,当前的false
将抛出的异常替换为返回值var sharedBulkhead = /* as before */;
var retryPolicy = /* as before */;
var fallbackForCircuitBreaker = /* as before */;
var logCircuitBreakerBrokenPerTry = Policy<bool>
.Handle<BrokenCircuitException>()
.FallbackAsync(
fallbackValue: false,
onFallbackAsync: (outcome, context) =>
{
Log.Error($"Operation attempted on broken circuit => Policy Wrap: {context.PolicyWrapKey}, Policy: {context.PolicyKey}, Endpoint: {context.OperationKey}");
throw outcome.Exception;
}
);
var fallbackForAnyException = /* as before */;
var resilienceStrategy = Policy.WrapAsync(retryPolicy, logCircuitBreakerBrokenPerTry, circuitBreaker, sharedBulkhead);
var policyWrap = fallbackForAnyException.WrapAsync(fallbackForCircuitBreaker.WrapAsync(resilienceStrategy));
,而这听起来像是您从每次尝试回退中寻求的是“日志,然后进行下一次尝试” 。这样做的技术是使用后备作为log then rethrow,以便您的重试策略仍然可以响应(重新抛出)异常。所以:
BulkheadRejectedException
我可以修改重试策略来处理批量拒绝吗?
Polly bulkhead documentation声明策略抛出var retryPolicy = Policy
.Handle<HttpRequestException>()
.Or<BrokenCircuitException>()
.Or<BulkheadRejectedException>()
/* etc */
,所以:
static
理想情况下在onBulkheadRejectedAsync上要做什么?
您可以登录。广义上讲,您可以减轻多余的负载,也可以将隔板抑制作为触发来水平扩展以增加容量。 Polly文档提供了更多讨论here和here。
此外,我正在使用sharedBulkHead,它是服务中的实例字段,并在构造函数中初始化。这是一个好习惯吗?
这取决于。 Bulkhead策略实例的生存期必须为long-lived across the governed calls,而不是每个调用,以确保Bulkhead策略实例的状态控制并发执行的调用数。