C# 在重试失败后,使用Polly在不同的URL上重试

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

我正在.Net Core中进行概念验证,这是polly的新手,我很难理解如何以定义重试策略的方式对其进行配置,但失败后,我们切换到其他url并对此进行重试(可能有许多url,可用url的列表是动态的)

我的首选是使用HttpClientFactory和这里描述的类型化客户端

我看过

但无法看到如何将这些应用于动态列表和HttpClientFactory/类型化客户端方法

// 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);
}
它是基于在运行时更改请求中的头的