【发布时间】:2019-07-31 22:03:51
【问题描述】:
我正在 .Net Core 中进行概念验证,并且是 polly 的新手,并且努力了解如何以定义重试策略的方式对其进行配置,但是在此失败后,我们切换到不同的 url 和重试(可能有很多,可用的 Url 列表是动态的)
我的偏好是使用此处描述的 HttpClientFactory 和 Typed Clients https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.1#typed-clients
我看过 https://github.com/App-vNext/Polly/issues/199
https://github.com/App-vNext/Polly/issues/591
但不知道如何将这些应用到动态列表和在 HttpClientFactory/ Typed Client 方法中
// Attempting to enable dynamic clients
// https://github.com/App-vNext/Polly/issues/199
// https://github.com/App-vNext/Polly/issues/591 using HttpClientfactory
services.AddHttpClient<IAppointmentServiceClient, AppointmentServiceClient>()
.ConfigureHttpClient((serviceProvider, client) =>
{
var serverList = ServiceRegistration.LocateServiceList("AppointmentService").Result;
var random = new Random();
int index = random.Next(serverList.Count);
var baseAddress = new Uri($"http://{ serverList[index]}");
client.BaseAddress = baseAddress;
})
.AddPolicyHandler(GetRetryPolicy())
//.AddPolicyHandler(GetCircuitBreakerPolicy());
.AddPolicyHandler((sp, req, key) =>
{
return GetCircuitBreakerPolicy();
},
GetPolicyKey
);
}
static string GetPolicyKey(HttpRequestMessage httpRequestMessage)
{
return httpRequestMessage.RequestUri.Authority;
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
onRetryAsync: async (outcome, timespan, retryCount, context) => {
context["RetriesInvoked"] = retryCount; // allows us to capture the reties downstream, potential for extra logging
});
}
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30),
onBreak: (ex, breakDelay, context) =>
{
},
onReset: (context)=>
{
},
onHalfOpen: () => { }
);
}
实际调用只是
public AppointmentServiceClient(HttpClient httpClient)
{
_apiClient = httpClient;
}
public async Task<IEnumerable<AppointmentEntity>> GetResourceAppointments(string resourceId, DateTimeOffset date)
{
var url = GetResourceAppointmentsUrl(resourceId, date);
var context = new Polly.Context();
//context["baseUrls"] = _serverList;
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
request.SetPolicyExecutionContext(context);
var response = await _apiClient.SendAsync(request);
context = response.RequestMessage?.GetPolicyExecutionContext(); // (if not already held in a local variable)
//if (context?.TryGetValue("RetriesInvoked", out int? retriesNeeded) ?? false)
//{
// // Do something with int? retriesNeeded
//}
response.EnsureSuccessStatusCode();
var appointmentResponse = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<IEnumerable<AppointmentEntity>>(appointmentResponse);
}
【问题讨论】: