Polly FallbackPolicy with Refit and HttpClientFactory



我使用HttpClientFactory和Refit一起进行API调用。我想使用Polly进行重试,断路器和回退,虽然设置重试和断路器很容易,但我与回退斗争,因为它只能返回类型HttpResponseMessage的回退值,但返回的是Refit.ApiResponse。我试着返回一个假的HttpResponseMessage,但随后Refit中断,因为它期望某些事情存在,例如HttpRequestMessage

当使用HttpClientFactory与Refit时,是否有人成功返回自定义对象作为回退值?

这是重试的初始设置:

PolicyBuilder<HttpResponseMessage>? policyBuilder = Policy<HttpResponseMessage>
.Handle<Exception>();
IEnumerable<TimeSpan>? retryDelays = Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(1), retryCount: 5, fastFirst:true);
AsyncRetryPolicy<HttpResponseMessage>? retryPolicy = policyBuilder.WaitAndRetryAsync(retryDelays, (exception, timeSpan, retryCount, context) =>
{
Debug.WriteLine($"Exception occurred while called Account Service. Retry policy in effect | Retry Attempt: {retryCount} | WaitSeconds: {timeSpan.TotalSeconds}. Exception: {exception.Exception.Message}");
});

这是断路器:

AsyncCircuitBreakerPolicy<HttpResponseMessage>? circuitBreakerPolicy = policyBuilder
.CircuitBreakerAsync(breakCircuitAfterErrors, TimeSpan.FromMinutes(keepCircuitBreakForMinutes),
(exception, timespan, context) =>
{
// OnBreak, i.e. when circuit state changes to open
Debug.WriteLine(
$"Account Service circuit breaker policy in effect | State changed to Open (blocked). It will remain open for {keepCircuitBreakForMinutes} minutes");
},
(context) =>
{
// OnReset, i.e. when circuit state changes to closed
Debug.WriteLine("Account Service circuit breaker policy in effect | State changed to Closed (normal).");
});

这是HttpResponseMessage的回退,它打破了Refit:

AsyncFallbackPolicy<HttpResponseMessage> fallbackPolicyForCircuitBreaker = Policy<HttpResponseMessage>
.Handle<BrokenCircuitException>()
.FallbackAsync((cancellationToken) =>
{
// In our case we return a null response.
Debug.WriteLine($"The Circuit is Open (blocked). A fallback null value is returned. Try again later.");
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
});

这里我将策略处理程序添加到客户端:

builder.Services.AddHttpClient("AccountService")
.AddPolicyHandler(fallbackPolicyForCircuitBreaker)
.AddPolicyHandler(retryPolicy)
.AddPolicyHandler(circuitBreakerPolicy);

FallbackAsync有几个过载。其中一个是这样的:

public static AsyncFallbackPolicy<TResult> FallbackAsync<TResult>(
this PolicyBuilder<TResult> policyBuilder, 
Func<DelegateResult<TResult>, Context, CancellationToken, Task<TResult>> fallbackAction, 
Func<DelegateResult<TResult>, Context, Task> onFallbackAsync)

这意味着在fallbackAction的情况下,您可以通过DelegateResult访问故障的HttpResponseMessage

.FallbackAsync(
fallbackAction:(dr, ctx, ct) => Task.FromResult(new HttpResponseMessage(dr.Result.StatusCode)),
onFallbackAsync:(dr, ctx) => Task.CompletedTask))

但请记住,dr.Result只有在没有例外的情况下才存在。否则.Result将是null,.Exception将包含抛出的异常。


如果你需要访问请求对象,那么你可以通过闭包来做。AddPolicyHandler有以下重载:

public static IHttpClientBuilder AddPolicyHandler (
this IHttpClientBuilder builder, 
Func<HttpRequestMessage,IAsyncPolicy<HttpResponseMessage>> policySelector);
public static IHttpClientBuilder AddPolicyHandler (
this IHttpClientBuilder builder, 
Func<IServiceProvider,HttpRequestMessage,IAsyncPolicy<HttpResponseMessage>> policySelector);

因此,在注册期间,您可以执行以下操作:

.AddPolicyHandler(req => Policy<HttpResponseMessage>
.Handle<BrokenCircuitException>()
.FallbackAsync((...) =>
{
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) { RequestMessage = req });
}, ...));

相关内容

  • 没有找到相关文章

最新更新