如何在不执行请求的情况下获取 polly 断路器状态



我知道我们可以使用电路状态在上下文中获取当前状态。 但是有没有办法让我在上下文之外获取电路状态。 例如,在下面 如果我想在控制器上获取电路状态,我该怎么做? 现在我在策略中设置了一个静态变量,但是当电路损坏时,它的上下文不是可供获取。这是我目前的设置。

启动

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddHttpClient<IIntCall, IntCall>().WrapResilientPolicies();
}

接口

public interface IIntCall
{
Task<bool> DoSomething();
}

实现:

public class IntCall : IIntCall
{
private readonly HttpClient client;
public IntCall(HttpClient httpClient)
{
this.client = httpClient;
}
public async Task<bool> DoSomething()
{
var response = await client.GetAsync("http://www.onegoogle.com");
var content = await response.Content.ReadAsStringAsync();
return false;
}
}

波莉实施

public static class CBExtensions
{
public static void WrapResilientPolicies(this IHttpClientBuilder builder)
{
builder.AddPolicyHandler((service, request) =>
GetRetryPolicy().WrapAsync(GetCircuitBreakerPolicy()));
}
private static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions.HandleTransientHttpError()
.CircuitBreakerAsync(3, TimeSpan.FromSeconds(30), (result, retryAttempt) =>
{
Debug.WriteLine("circuit broken");
},
() =>
{
Debug.WriteLine("circuit closed");
});
}
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions.HandleTransientHttpError()
.Or<Exception>(e => !(e is BrokenCircuitException))
.WaitAndRetryAsync(3,
retryAttempt => TimeSpan.FromMilliseconds(500),
onRetry: (context, attempt) =>
{
Debug.WriteLine("error");
}
);
}

}

CircuitState属性在策略实例实现的ICircuitBreaker接口上可用:(更多内容在 Polly 自述文件和 wiki 中(

CircuitState state = breaker.CircuitState;
/*
CircuitState.Closed
CircuitState.Open
CircuitState.HalfOpen
CircuitState.Isolated
*/

其中breaker是策略实例,即最初由GetCircuitBreakerPolicy()方法返回的策略。


您可以通过 DI 将该断路器策略传递给控制器。 在启动期间,您可以执行以下操作:

var breaker = GetCircuitBreakerPolicy();
services.AddSingleton<ICircuitBreakerPolicy<HttpResponseMessage>>(breaker as ICircuitBreakerPolicy<HttpResponseMessage>);

当然,您需要在调用.AddPolicyHandler(...)时使用相同的单个breaker实例,而不是制造新的/不同的实例。

builder.AddPolicyHandler(GetRetryPolicy().WrapAsync(breaker));

然后,控制器可以通过构造函数注入接收断路器实例的副本:

public class MyController
{
public MyController(ICircuitBreakerPolicy<HttpResponseMessage> breaker, /* etc */)
{
}
}

如果应用程序仅使用单个断路器实例,则通过在 DI 容器上注册ICircuitBreakerPolicy<HttpResponseMessage>将断路器传递给控制器(如上图所示(效果很好。

如果您有多个断路器策略实例,这些实例需要在应用程序周围的其他位置(例如由控制器(直接访问,请将它们存储在PolicyRegistry中,并通过 DI 将IReadOnlyPolicyRegistry<string>传递给控制器。 使用PolicyRegistry中的策略配置HttpClient存在.AddPolicyHandlerFromRegistry()重载。

这个问题的标题是一般性的,没有"不使用静态变量"的约束。对于没有该约束的其他内容:

public class SomeHandler
{
private static readonly Polly.CircuitBreaker.AsyncCircuitBreakerPolicy _circuitBreakerPolicy
= Policy.Handle<Exception>().CircuitBreakerAsync(3, TimeSpan.FromMinutes(2));
public async Task Handle(IRequest request)
{
if (_circuitBreakerPolicy.CircuitState == Polly.CircuitBreaker.CircuitState.Open)
{
logger.LogInformation("The '_circuitBreakerPolicy' disallows SomeHandler to handle any requests now.");
return;
}
var wrappedPolicy = Policy.WrapAsync(GetRetryPolicy(), _circuitBreakerPolicy);
await wrappedPolicy.ExecuteAsync(...)
}
...
}

相关内容

最新更新