Polly 的 Policy.TimeoutAsync 在异步上下文中无法与 PolicyWrap 一起使用
Polly's Policy.TimeoutAsync does not work with PolicyWrap in an async context
这是一个完整的示例(Copy/paste 它可以玩,只需获取 Polly Nuget)
我有以下控制台应用程序代码,它向“http://ptsv2.com/t/v98pb-1521637251/post' (you can visit this link "http://ptsv2.com/t/v98pb-1521637251”上的 HTTP 客户端沙箱发出 POST 请求,以查看配置或使自己成为 "toilet"):
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);
}
}
Http 客户端等待 4 秒,然后 returns 响应。
我已经设置了这样的策略(超时策略设置为等待 1 秒响应):
public static class Policies
{
public static TimeoutPolicy<HttpResponseMessage> TimeoutPolicy
{
get
{
return Policy.TimeoutAsync<HttpResponseMessage>(1, onTimeoutAsync: (context, timeSpan, task) =>
{
Console.WriteLine("Timeout delegate fired after " + timeSpan.TotalMilliseconds);
return Task.CompletedTask;
});
}
}
public static RetryPolicy<HttpResponseMessage> RetryPolicy
{
get
{
return Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.Or<TimeoutRejectedException>()
.RetryAsync(3, onRetryAsync: (delegateResult, i) =>
{
Console.WriteLine("Retry delegate fired for time No. " + i);
return Task.CompletedTask;
});
}
}
public static FallbackPolicy<HttpResponseMessage> FallbackPolicy
{
get
{
return Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.Or<TimeoutRejectedException>()
.FallbackAsync(new HttpResponseMessage(HttpStatusCode.InternalServerError), onFallbackAsync: (delegateResult, context) =>
{
Console.WriteLine("Fallback delegate fired");
return Task.CompletedTask;
});
}
}
public static PolicyWrap<HttpResponseMessage> PolicyWrap
{
get
{
return Policy.WrapAsync(FallbackPolicy, RetryPolicy, TimeoutPolicy);
}
}
}
但是,onTimeoutAsync 委托根本没有被命中,控制台打印出以下内容:
Retry delegate fired for time No. 1 //Hit after 4 seconds
Retry delegate fired for time No. 2 //Hit after 4 more seconds
Retry delegate fired for time No. 3 //Hit after 4 more seconds
Fallback delegate fired
Unsuccessful
它包含在PolicyWrap中并且是异步的,我不知道为什么它没有被命中。
非常感谢任何信息。
Polly Timeout policy with the default TimeoutStrategy.Optimistic
operates by timing-out CancellationToken
, so the delegates you execute must respond to co-operative cancellation. See the Polly Timeout wiki 了解更多详情。
将您的执行行更改为以下应该使超时有效:
var response = await Policies.PolicyWrap.ExecuteAsync(
async ct => await _httpClient.PostAsync(/* uri */, new StringContent(request), ct).ConfigureAwait(false),
CancellationToken.None // CancellationToken.None here indicates you have no independent cancellation control you wish to add to the cancellation provided by TimeoutPolicy. You can also pass in your own independent CancellationToken.
);
默认情况下 Polly 异步执行 do not continue on captured synchronization context(它们以 .ConfigureAwait(false)
执行),因此也可以缩短为:
var response = await Policies.PolicyWrap.ExecuteAsync(
ct => _httpClient.PostAsync(/* uri */, new StringContent(request), ct),
CancellationToken.None
);
这是一个完整的示例(Copy/paste 它可以玩,只需获取 Polly Nuget)
我有以下控制台应用程序代码,它向“http://ptsv2.com/t/v98pb-1521637251/post' (you can visit this link "http://ptsv2.com/t/v98pb-1521637251”上的 HTTP 客户端沙箱发出 POST 请求,以查看配置或使自己成为 "toilet"):
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);
}
}
Http 客户端等待 4 秒,然后 returns 响应。
我已经设置了这样的策略(超时策略设置为等待 1 秒响应):
public static class Policies
{
public static TimeoutPolicy<HttpResponseMessage> TimeoutPolicy
{
get
{
return Policy.TimeoutAsync<HttpResponseMessage>(1, onTimeoutAsync: (context, timeSpan, task) =>
{
Console.WriteLine("Timeout delegate fired after " + timeSpan.TotalMilliseconds);
return Task.CompletedTask;
});
}
}
public static RetryPolicy<HttpResponseMessage> RetryPolicy
{
get
{
return Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.Or<TimeoutRejectedException>()
.RetryAsync(3, onRetryAsync: (delegateResult, i) =>
{
Console.WriteLine("Retry delegate fired for time No. " + i);
return Task.CompletedTask;
});
}
}
public static FallbackPolicy<HttpResponseMessage> FallbackPolicy
{
get
{
return Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.Or<TimeoutRejectedException>()
.FallbackAsync(new HttpResponseMessage(HttpStatusCode.InternalServerError), onFallbackAsync: (delegateResult, context) =>
{
Console.WriteLine("Fallback delegate fired");
return Task.CompletedTask;
});
}
}
public static PolicyWrap<HttpResponseMessage> PolicyWrap
{
get
{
return Policy.WrapAsync(FallbackPolicy, RetryPolicy, TimeoutPolicy);
}
}
}
但是,onTimeoutAsync 委托根本没有被命中,控制台打印出以下内容:
Retry delegate fired for time No. 1 //Hit after 4 seconds
Retry delegate fired for time No. 2 //Hit after 4 more seconds
Retry delegate fired for time No. 3 //Hit after 4 more seconds
Fallback delegate fired
Unsuccessful
它包含在PolicyWrap中并且是异步的,我不知道为什么它没有被命中。 非常感谢任何信息。
Polly Timeout policy with the default TimeoutStrategy.Optimistic
operates by timing-out CancellationToken
, so the delegates you execute must respond to co-operative cancellation. See the Polly Timeout wiki 了解更多详情。
将您的执行行更改为以下应该使超时有效:
var response = await Policies.PolicyWrap.ExecuteAsync(
async ct => await _httpClient.PostAsync(/* uri */, new StringContent(request), ct).ConfigureAwait(false),
CancellationToken.None // CancellationToken.None here indicates you have no independent cancellation control you wish to add to the cancellation provided by TimeoutPolicy. You can also pass in your own independent CancellationToken.
);
默认情况下 Polly 异步执行 do not continue on captured synchronization context(它们以 .ConfigureAwait(false)
执行),因此也可以缩短为:
var response = await Policies.PolicyWrap.ExecuteAsync(
ct => _httpClient.PostAsync(/* uri */, new StringContent(request), ct),
CancellationToken.None
);