我正在尝试利用Polly处理任意结果条件的能力https://github.com/App-vNext/Polly/#step-1b-optionally-specify-return-results-you-want-to-处理。
在我的测试用例中,我使用RestSharp发出 HTTP 请求。这是我的示例代码:
var policy = Policy
.HandleResult<IRestResponse>(r => r.Content.Contains("bla"))
.Retry(2)
.ExecuteAndCapture(() =>
{
IRestClient client = new RestClient("https://httpbin.org/anything");
IRestRequest request = new RestRequest(Method.GET);
var response = client.Execute(request);
return response;
});
Run Code Online (Sandbox Code Playgroud)
对https://httpbin.org/anything的调用回响了一堆东西 - 确切的内容并不相关。正如您在谓词中看到的,我在结果正文中寻找字符串“bla”。
问题是,policy.Outcome是总是成功的(policy.Outcome == OutcomeType.Successful),但“喇嘛”是不是在结果身体。
这是一个完全有效的示例(复制/粘贴它并尝试一下,只需获取 Polly Nuget)
我有以下控制台应用程序代码,它向“ http://ptsv2.com/t/v98pb-1521637251/post ”上的 HTTP 客户端沙箱发出 POST 请求(您可以访问此链接“ http://ptsv2.com/ t/v98pb-1521637251 “查看配置或让自己成为一个“厕所”):
class Program
{
private static readonly HttpClient _httpClient = new HttpClient()
; //WHY? BECAUSE - https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
static void Main(string[] args)
{
_httpClient.BaseAddress = new Uri(@"http://ptsv2.com/t/v98pb-1521637251/post");
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));
var result = ExecuteAsync("Test").Result;
Console.WriteLine(result);
Console.ReadLine();
}
private static async Task<string> ExecuteAsync(string request)
{
var response = await Policies.PolicyWrap.ExecuteAsync(async () => await _httpClient.PostAsync("", new StringContent(request)).ConfigureAwait(false));
if (!response.IsSuccessStatusCode)
return "Unsuccessful";
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
}
Run Code Online (Sandbox Code Playgroud)
Http 客户端等待 4 秒,然后返回响应。
我已经设置了这样的策略( …
如果 HTTP 调用失败,我在非常基本的场景中使用 Polly 进行指数退避:
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return await HandleTransientHttpError()
.Or<TimeoutException>()
.WaitAndRetryAsync(4, retryAttempt => TimeSpan.FromSeconds(Math.Pow(3, retryAttempt)))
.ExecuteAsync(async () => await base.SendAsync(request, cancellationToken).ConfigureAwait(false));
}
private static PolicyBuilder<HttpResponseMessage> HandleTransientHttpError()
{
return Policy
.HandleResult<HttpResponseMessage>(response => (int)response.StatusCode >= 500 || response.StatusCode == System.Net.HttpStatusCode.RequestTimeout)
.Or<HttpRequestException>();
}
Run Code Online (Sandbox Code Playgroud)
我有一个测试 API,它只是HttpListener在while(true). 目前,我正在尝试测试客户端在每次调用收到 500 时是否正确重试。
while (true)
{
listener.Start();
Console.WriteLine("Listening...");
HttpListenerContext context = listener.GetContext();
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
response.StatusCode = (int)HttpStatusCode.InternalServerError;
//Thread.Sleep(1000 * 1); …Run Code Online (Sandbox Code Playgroud) 我对 Polly 很陌生,所以与我尝试做的方法相比,可能有一种完全不同的方法,那是完全可以的。
我的目标是这样的:
token可能因超时或请求而被取消token取消。尽管我使用的方法似乎缺少一些东西,并且可能有更好/更干净的方法来完成我想要的事情。我特别想到这一行.WaitAndRetryForever(retryAttempt => TimeSpan.Zero,。我觉得我应该能够通过retryDelay这里而不是TimeSpan.Zero,但如果我在请求取消时这样做,它不会返回,直到retryDelay完成等待,而不是像我想要的那样立即返回。
我确实看到 .Execute 看起来可以使用取消令牌执行某些操作,但我不知道如何使用它,所以如果这是我的答案,请忽略我的其他漫谈。
以防万一 Polly NuGet 开发人员看到这一点,我期望看到的是一个重载,因为WaitAndRetryForever它将取消令牌作为参数,以便在被取消时它可以立即返回。我犹豫是否将此作为正式建议,因为我对波莉来说太陌生了,我不确定这是否有意义。
这是我目前正在使用的方法:
internal static void Retry(Action action, TimeSpan retryDelay, CancellationToken token)
{
try
{
Policy
.Handle<IOException>()
.WaitAndRetryForever(retryAttempt => TimeSpan.Zero,
(ex, delay, context) =>
{
Task.Delay(retryDelay, token).GetAwaiter().GetResult();
token.ThrowIfCancellationRequested();
//Log exception here
})
.Execute(() =>
{
token.ThrowIfCancellationRequested();
action.Invoke();
});
}
catch (OperationCanceledException)
{
//Log cancellation here
throw;
}
catch (Exception ex)
{
//Log …Run Code Online (Sandbox Code Playgroud) 我正在寻找HttpClient对 a进行单元测试Polly RetryPolicy,并且我正在尝试找出如何控制响应的内容HTTP。
我在客户端上使用了 a HttpMessageHandler,然后覆盖发送异步,这效果很好,但是当我添加 Polly 重试策略时,我必须使用 a 创建 HTTP 客户端的实例IServiceCollection,并且无法HttpMessageHandler为客户端创建 a。我尝试过使用,.AddHttpMessageHandler()但这会阻止轮询重试策略,并且只会触发一次。
这就是我在测试中设置 HTTP 客户端的方式
IServiceCollection services = new ServiceCollection();
const string TestClient = "TestClient";
services.AddHttpClient(name: TestClient)
.AddHttpMessageHandler()
.SetHandlerLifetime(TimeSpan.FromMinutes(5))
.AddPolicyHandler(KYA_GroupService.ProductMessage.ProductMessageHandler.GetRetryPolicy());
HttpClient configuredClient =
services
.BuildServiceProvider()
.GetRequiredService<IHttpClientFactory>()
.CreateClient(TestClient);
public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(6,
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
onRetryAsync: OnRetryAsync);
}
private async static Task OnRetryAsync(DelegateResult<HttpResponseMessage> outcome, TimeSpan timespan, int retryCount, Context context)
{ …Run Code Online (Sandbox Code Playgroud) 我正在使用 Polly 重试 HttpClient 尝试:
\n services.AddHttpClient<JoinPackageApiClient>(jp => { jp.BaseAddress = new Uri(appSettings.JoinPackageWS.BaseUrl); })\n .AddPolicyHandler(GetRetryPolicy(appSettings, serviceProvider))\nRun Code Online (Sandbox Code Playgroud)\n哪里 GetRetryPolicy:
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy(AppSettings appSettings, ServiceProvider serviceProvider)\n {\n return HttpPolicyExtensions\n .HandleTransientHttpError()\n .OrResult(msg => msg.StatusCode != HttpStatusCode.OK)\n .Or<TimeoutRejectedException>()\n .Or<TaskCanceledException>()\n .Or<OperationCanceledException>()\n\n .WaitAndRetryAsync(appSettings.PollySettings.RetryAttempts, (retryAttempt, c) =>\n {\n\n return TimeSpan.FromSeconds(2);\n }, onRetry: (response, delay, retryCount, context) =>\n {\n\n //\xe2\x96\x88how can I access the full(!) HttpClient's URI here ?\n //e.g. : https://a.com/b/c?d=1\n \n });\n }\nRun Code Online (Sandbox Code Playgroud)\n问题:
\n查看该onRetry参数,我想在该onRetry部分中记录完整的 URL …
我正在尝试包装两个 Polly 策略并想要返回IAsyncPolicy,但它给出了错误,
从 Polly.Retry.RetryPolicy < System.Net.Http.HttpResponseMessage> 转换为 Polly.IAsyncPolicy
public static IAsyncPolicy CreateDefaultRetryPolicy()
{
var timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromSeconds(180));
var waitAndRetryPolicy = Polly.Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError)
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(3, retryAttempt)),
(result, timeSpan, context) =>
{
});
return Policy.WrapAsync(timeoutPolicy, waitAndRetryPolicy);
}
Run Code Online (Sandbox Code Playgroud)
如何包装并返回?
执行策略时,我看到有些人这样调用 ExecuteAsync:
...
.ExecuteAsync(async (ct) => await GetEmployeeAsync(employeeId, ct), cancellationToken);
Run Code Online (Sandbox Code Playgroud)
像这样:
...
.ExecuteAsync(ct => GetEmployeeAsync(employeeId, ct), cancellationToken);
Run Code Online (Sandbox Code Playgroud)
有什么区别以及应该使用哪一种?
我有一个 ASP.NET Core 3.1 Web API 服务,它正在接收 Web 请求,对其进行一些操作,然后将其传递到后端服务并同步返回响应。它工作正常,但我想为这些后端请求引入一些重试逻辑,以防出现一些问题。
我正在使用类型化的 HttpClient 并尝试使用 Polly 来实现重试逻辑: https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory#using-polly-with-ihttpclientfactory
当后端服务工作时,一切似乎都很好,但不幸的是,每当我的后端返回诸如 500 内部服务器错误之类的错误时,我都会收到以下异常:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware: Error: An unhandled exception has occurred while executing the request.
System.Net.Http.HttpRequestException: An error occurred while sending the request.
---> System.InvalidOperationException: The stream was already consumed. It cannot be read again.
at System.Net.Http.StreamContent.PrepareContent()
at System.Net.Http.StreamContent.SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken)
at System.Net.Http.HttpContent.CopyToAsync(Stream stream, TransportContext context, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.SendRequestContentAsync(HttpRequestMessage request, HttpContentWriteStream stream, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
--- End of …Run Code Online (Sandbox Code Playgroud) 我使用 Polly 来处理一些场景,例如请求限制和超时。这些策略直接添加到 Startup.cs 中,如下所示:
var retries = //applying the retries, let say I set to 25 times with 10s delay. Total 250s.
serviceCollection
.AddHttpClient<IApplicationApi, ApplicationApi>()
.AddPolicyHandler((services, request) => GetRetryPolicy<ApplicationApi>(retries, services));
Run Code Online (Sandbox Code Playgroud)
政策:
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy<T>(List<TimeSpan> retries, IServiceProvider services)
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(retries,
onRetry: (outcome, timespan, retryAttempt, context) =>
{
//do some logging
}
}
Run Code Online (Sandbox Code Playgroud)
在 ApplicationApi.cs 中执行如下操作:
private readonly HttpClient _httpClient;
public ApplicationApi(HttpClient httpClient)
{
_httpClient = httpClient;
}
public void CallApi()
{
var …Run Code Online (Sandbox Code Playgroud) c# ×10
polly ×10
retry-logic ×4
.net ×3
.net-core ×2
timeout ×2
asp.net-core ×1
asynchronous ×1
policywrap ×1
restsharp ×1
unit-testing ×1