如何在不执行请求的情况下获取 polly 断路器状态
How to get the polly circuit breaker state without executing the requests
我知道我们可以使用电路状态来获取上下文中的当前状态。但是有没有一种方法可以让我在上下文之外获得电路状态。例如在下面如果我想在控制器上获取电路状态我该怎么做?现在我在策略中设置了一个静态变量,但是当电路断开时,它的上下文无法获取。这是我当前的设置。
启动
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;
}
}
Polly 实施
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 readme and 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(...)
时使用 ,而不是制造 new/different。
builder.AddPolicyHandler(GetRetryPolicy().WrapAsync(breaker));
控制器然后可以通过构造函数注入接收断路器实例的副本:
public class MyController
{
public MyController(ICircuitBreakerPolicy<HttpResponseMessage> breaker, /* etc */)
{
}
}
如果应用程序仅使用单个断路器实例,则通过在 DI 容器上注册 ICircuitBreakerPolicy<HttpResponseMessage>
将断路器传递给控制器(如上所示)效果很好。
如果您有多个断路器策略实例需要在应用程序的其他地方直接访问,例如通过控制器,将它们存储在 PolicyRegistry
, and pass the IReadOnlyPolicyRegistry<string>
to the controller by DI. There are .AddPolicyHandlerFromRegistry()
overloads 中,以便使用 HttpClient
中的策略配置 PolicyRegistry
.
我知道我们可以使用电路状态来获取上下文中的当前状态。但是有没有一种方法可以让我在上下文之外获得电路状态。例如在下面如果我想在控制器上获取电路状态我该怎么做?现在我在策略中设置了一个静态变量,但是当电路断开时,它的上下文无法获取。这是我当前的设置。
启动
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;
}
}
Polly 实施
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 readme and 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(...)
时使用
builder.AddPolicyHandler(GetRetryPolicy().WrapAsync(breaker));
控制器然后可以通过构造函数注入接收断路器实例的副本:
public class MyController
{
public MyController(ICircuitBreakerPolicy<HttpResponseMessage> breaker, /* etc */)
{
}
}
如果应用程序仅使用单个断路器实例,则通过在 DI 容器上注册 ICircuitBreakerPolicy<HttpResponseMessage>
将断路器传递给控制器(如上所示)效果很好。
如果您有多个断路器策略实例需要在应用程序的其他地方直接访问,例如通过控制器,将它们存储在 PolicyRegistry
, and pass the IReadOnlyPolicyRegistry<string>
to the controller by DI. There are .AddPolicyHandlerFromRegistry()
overloads 中,以便使用 HttpClient
中的策略配置 PolicyRegistry
.