如何使用Polly启用超时策略

时间:2019-04-01 16:46:53

标签: c# polly

我正在尝试使用polly设置超时策略。

    static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        timeoutPolicy().GetAwaiter().GetResult();

        stopwatch.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
        Console.ReadKey();
    }

    static async Task timeoutPolicy()
    {
        AsyncTimeoutPolicy<HttpResponseMessage> timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(1); // setup the timeout limit to be 1 sec

        HttpResponseMessage response = await timeoutPolicy.ExecuteAsync((ct) => LongOperation(), CancellationToken.None);

    }

    static Task<HttpResponseMessage> LongOperation()
    {
        return Task<HttpResponseMessage>.Factory.StartNew(() =>
        {
            Thread.Sleep(5000); // Sleep 5 seconds
            return new HttpResponseMessage()
            {
                StatusCode = HttpStatusCode.BadRequest
            };

        });
    }

我希望在1秒钟后引发异常,因为这是我设置的超时上限。但是目前,不会引发任何异常,并且LongOperation()方法会在大约5秒钟后正常返回。

为什么在这种情况下超时策略不起作用?

2 个答案:

答案 0 :(得分:0)

现在您正在使用Optimistic超时,该超时期望您调用的代理尊重并响应取消令牌。您的代表不需要,在这种情况下,您需要使用Pessimistic超时来确保您的呼叫者不会等待经过定义的超时。

static async Task timeoutPolicy()
{
    var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(1, TimeoutStrategy.Pessimistic); // setup the timeout limit to be 1 sec

    HttpResponseMessage response = await timeoutPolicy.ExecuteAsync((ct) => LongOperation(), CancellationToken.None);

} 
文档Optimistic中所述的

Polly Timeout是默认设置。

正如@moutain旅行者已经指出的那样,乐观的超时要求您通过并与超时取消合作。使用HttpClient的api调用已经解决了这个问题,但是在此示例示例中,您的代码将如下所示:

static async Task timeoutPolicy()
{
    var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(1, TimeoutStrategy.Optimistic); // setup the timeout limit to be 1 sec

    HttpResponseMessage response = await timeoutPolicy.ExecuteAsync((ct) => LongOperation(ct), CancellationToken.None);

}

static Task<HttpResponseMessage> LongOperation(CancellationToken token)
{
    return Task<HttpResponseMessage>.Factory.StartNew(() =>
    {
        var longTask = Task.Delay(5000);
        while (!longTask.IsCompleted)
        {
            token.ThrowIfCancellationRequested();
        }
        return new HttpResponseMessage()
        {
            StatusCode = HttpStatusCode.BadRequest
        };

    });
} 

答案 1 :(得分:0)

  

为什么在这种情况下超时策略不起作用?

Polly的TimeoutPolicy存在两种模式:

乐观模式是默认模式,因此您发布的代码使用此模式。但是(a)所发布代码中的LongOperation()不能响应合作取消;因此该政策不会超时。

具有异步策略的悲观模式为intentionally designed only to govern delegates which conform to the normal async pattern。发布的Thread.Sleep()中的LongOperation()是完全同步的;因此您的示例仅通过切换到TimeoutStrategy.Pessimistic就不会超时。


TimeoutStrategy.Optimistic是通过HttpClient进行呼叫的最佳模拟,因为这些呼叫确实会响应CancellationToken

可以通过await Task.Delay(...)兑现CancellationTokenlike this来模拟异步超时策略的长时间操作超时模式:

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Polly;
using Polly.Timeout;

public class Program
{ 
    public static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        try {
            timeoutPolicy().GetAwaiter().GetResult();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

        stopwatch.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
    }

    static async Task timeoutPolicy()
    {
        var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(1); // setup the timeout limit to be 1 sec

        HttpResponseMessage response = await timeoutPolicy.ExecuteAsync((ct) => LongOperation(ct), CancellationToken.None);
    }

    static async Task<HttpResponseMessage> LongOperation(CancellationToken token)
    {
        await Task.Delay(5000, token);
        return new HttpResponseMessage()
        {
            StatusCode = HttpStatusCode.BadRequest
        };
    }
}