C# 在重试失败后,使用Polly在不同的URL上重试
我正在.Net Core中进行概念验证,这是polly的新手,我很难理解如何以定义重试策略的方式对其进行配置,但失败后,我们切换到其他url并对此进行重试(可能有许多url,可用url的列表是动态的) 我的首选是使用HttpClientFactory和这里描述的类型化客户端 我看过 但无法看到如何将这些应用于动态列表和HttpClientFactory/类型化客户端方法C# 在重试失败后,使用Polly在不同的URL上重试,c#,.net-core,polly,C#,.net Core,Polly,我正在.Net Core中进行概念验证,这是polly的新手,我很难理解如何以定义重试策略的方式对其进行配置,但失败后,我们切换到其他url并对此进行重试(可能有许多url,可用url的列表是动态的) 我的首选是使用HttpClientFactory和这里描述的类型化客户端 我看过 但无法看到如何将这些应用于动态列表和HttpClientFactory/类型化客户端方法 // Attempting to enable dynamic clients // https://github.co
// 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: () => { }
);
}
//正在尝试启用动态客户端
// https://github.com/App-vNext/Polly/issues/199
// https://github.com/App-vNext/Polly/issues/591 使用HttpClientfactory
services.AddHttpClient()
.ConfigureHttpClient((服务提供商,客户端)=>
{
var serverList=ServiceRegistration.LocateServiceList(“AppointmentService”).Result;
var random=新的random();
int index=random.Next(serverList.Count);
var baseAddress=新Uri($“http://{serverList[index]}”);
client.BaseAddress=BaseAddress;
})
.AddPolicyHandler(GetRetryPolicy())
//.AddPolicyHandler(GetCircuitBreakerPolicy());
.AddPolicyHandler((sp、req、key)=>
{
返回GetCircuitBreakerPolicy();
},
GetPolicyKey
);
}
静态字符串GetPolicyKey(HttpRequestMessage HttpRequestMessage)
{
返回httpRequestMessage.RequestUri.Authority;
}
静态IAsyncPolicy GetRetryPolicy()
{
返回HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg=>msg.StatusCode==System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(3,retryAttenting=>TimeSpan.FromSeconds(Math.Pow(2,retryAttenting)),
onRetryAsync:async(结果、时间跨度、retryCount、上下文)=>{
context[“RetriesInvoked”]=retryCount;//允许我们捕获下游的RETIE,这可能会导致额外的日志记录
});
}
静态IAsyncPolicy GetCircuitBreakerPolicy()
{
返回HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(5,从秒开始的时间跨度(30),
onBreak:(例如,breakDelay,context)=>
{
},
onReset:(上下文)=>
{
},
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);
}
public-AppointmentServiceClient(HttpClient-HttpClient)
{
_apiClient=httpClient;
}
公共异步任务GetResourceAppointments(字符串resourceId、DateTimeOffset日期)
{
var url=GetResourceAppointmentsUrl(资源ID,日期);
var context=new Polly.context();
//上下文[“基本URL”]=\u服务器列表;
HttpRequestMessage请求=新的HttpRequestMessage(HttpMethod.Get,url);
SetPolicyExecutionContext(上下文);
var response=await _apiClient.sendsync(请求);
context=response.RequestMessage?.GetPolicyExecutionContext();/(如果尚未保存在局部变量中)
//if(上下文?.TryGetValue(“RetriesInvoked”,out int?Retriesineded)??false)
//{
////使用int执行某些操作?需要重试
//}
response.EnsureSuccessStatusCode();
var appointmentResponse=await response.Content.ReadAsStringAsync();
返回JsonConvert.DeserializeObject(appointmentResponse);
}
您是否查看了HttpClientFactory
的ConfigureHttpClient
扩展方法。它允许您配置工厂正在创建的HttpClient
这里有一些你可以试试的东西-
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddSingleton<IMyUrlList, MyUrlList>();
services.AddHttpClient("RemoteServer", client =>
{
client.DefaultRequestHeaders.Add("Accept", "application/json");
}).ConfigureHttpClient((serviceProvider, client) =>
{
IMyUrlList myUrlList = serviceProvider.GetService<IMyUrlList>();
client.BaseAddress = myUrlList.NextUrl();
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void配置服务(IServiceCollection服务)
{
services.AddMemoryCache();
services.AddSingleton();
services.AddHttpClient(“远程服务器”,客户端=>
{
client.DefaultRequestHeaders.Add(“Accept”、“application/json”);
}).ConfigureHttpClient((服务提供商,客户端)=>
{
imyurlist myurlist=serviceProvider.GetService();
client.BaseAddress=myurlist.NextUrl();
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
它是基于在运行时更改请求中的头的