Polly的Policy.TimeoutAsync在异步上下文中不适用于PolicyWrap [英] Polly's Policy.TimeoutAsync does not work with PolicyWrap in an async context

查看:574
本文介绍了Polly的Policy.TimeoutAsync在异步上下文中不适用于PolicyWrap的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个完整的示例(将其复制/粘贴并播放,只需获取Polly Nuget)

This is a FULLY working example (Copy/paste it and play around, just get the Polly Nuget)

我有以下控制台应用程序代码,该代码对" http://ptsv2.com/t/v98pb-1521637251/post "(您可以访问此链接"

I have the following Console app code which makes a POST request to an HTTP client sandbox on 'http://ptsv2.com/t/v98pb-1521637251/post' (you can visit this link "http://ptsv2.com/t/v98pb-1521637251" to see the configuration or make yourself a "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秒钟,然后返回响应.

The Http client waits for 4 seconds, then returns the response.

我已经这样设置了我的政策(超时政策已设置为等待1秒钟才能得到响应):

I have set up my Policies like this (timeout policy is set up to wait for 1 second for the response):

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委托,控制台会打印出以下内容:

However, onTimeoutAsync delegate is not being hit at all and the console prints out the following:

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中并且是异步的,我不知道为什么它没有被点击. 任何信息都将受到高度赞赏.

It is included in the PolicyWrap and is Async and I do not know why it is not being hit. Any information is highly appreciated.

推荐答案

Polly 超时政策(默认值为TimeoutStrategy.Optimistic)通过超时CancellationToken进行操作,因此您执行的委托必须响应 Polly Timeout Wiki .

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 for more detail.

将执行行更改为以下内容应使超时起作用:

Changing your execution line to the following should make the timeout work:

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异步执行不会在捕获的同步上下文上继续(它们会执行使用.ConfigureAwait(false)),因此也可以缩短为:

Polly async executions by default do not continue on captured synchronization context (they execute with .ConfigureAwait(false)), so this can also be shortened to:

var response = await Policies.PolicyWrap.ExecuteAsync(
    ct => _httpClient.PostAsync(/* uri */, new StringContent(request), ct), 
    CancellationToken.None
);

这篇关于Polly的Policy.TimeoutAsync在异步上下文中不适用于PolicyWrap的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆