C# 如何使用polly启用超时策略

C# 如何使用polly启用超时策略,c#,polly,C#,Polly,我正在和波利一起尝试超时策略 static void Main(string[] args) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); timeoutPolicy().GetAwaiter().GetResult(); stopwatch.Stop(); Console.WriteLine("Time elapsed:

我正在和波利一起尝试超时策略

    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
            };

        });
    }
static void Main(字符串[]args)
{
秒表秒表=新秒表();
秒表。开始();
timeoutPolicy().GetAwaiter().GetResult();
秒表;
WriteLine(“经过的时间:{0}”,stopwatch.appeased);
Console.ReadKey();
}
静态异步任务时间输出策略()
{
AsyncTimeoutPolicy timeoutPolicy=Policy.TimeoutAsync(1);//将超时限制设置为1秒
HttpResponseMessage response=等待时间输出策略.ExecuteAsync((ct)=>LongOperation(),CancellationToken.None);
}
静态任务长操作()
{
返回Task.Factory.StartNew(()=>
{
Thread.Sleep(5000);//睡眠5秒
返回新的HttpResponseMessage()
{
StatusCode=HttpStatusCode.BadRequest
};
});
}
我希望在经过1秒后抛出异常,因为这是我设置的超时上限。但目前不会抛出异常,方法LongOperation()在大约5秒后正常返回


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

现在您使用的是
乐观
超时,它期望您调用的delgate尊重并响应取消令牌。您的代理没有,在这种情况下,您需要使用
悲观
超时来确保调用方没有等待超过定义的超时

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);

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

波利的
TimeoutPolicy
有两种模式:

  • 期望受治理的代理响应
  • 允许调用代码离开等待未响应合作取消的代理
乐观模式是默认模式,因此您发布的代码使用此模式。但是(a)张贴代码中的
longooperation()
不响应合作取消;因此,该政策不会超时

异步策略的悲观模式是<发布的
LongOperation()
中的code>Thread.Sleep()是完全同步的;因此,您的示例不会因为切换到
TimeoutStrategy.悲观的
而超时


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

异步超时策略的乐观模式超时一个长操作可以通过
等待任务来模拟。延迟(…)
执行
取消令牌
,:

使用系统;
使用系统诊断;
Net系统;
使用System.Net.Http;
使用系统线程;
使用System.Threading.Tasks;
使用Polly;
使用Polly.Timeout;
公共课程
{ 
公共静态void Main(字符串[]args)
{
秒表秒表=新秒表();
秒表。开始();
试一试{
timeoutPolicy().GetAwaiter().GetResult();
}
捕获(例外e)
{
控制台写入线(e.Message);
}
秒表;
WriteLine(“经过的时间:{0}”,stopwatch.appeased);
}
静态异步任务时间输出策略()
{
var timeoutPolicy=Policy.TimeoutAsync(1);//将超时限制设置为1秒
HttpResponseMessage response=等待时间输出策略.ExecuteAsync((ct)=>LongOperation(ct),CancellationToken.None);
}
静态异步任务长操作(CancellationToken令牌)
{
等待任务。延迟(5000,令牌);
返回新的HttpResponseMessage()
{
StatusCode=HttpStatusCode.BadRequest
};
}
} 

如果我想保持乐观的超时策略,是否有解决办法@JStewardYes:取消已执行代表的荣誉合作。大多数通过HttpClient进行的异步调用都是这样的,因此,如果您的测试就是为了模拟这种情况而设计的,那么您可以预期,
HttpClient.fooancy(…)
确实尊重合作取消。本文提供了关于这些问题的更多细节。在Polly上,github的主题是为什么悲观超时不会取消
Thread.Sleep()
delegate(Thread.Sleep是同步阻塞的,而不是异步的,异步策略不是为超时而设计的)。但是,如果您打算模拟
HttpClient.fooancy(…)
方法,通过
CancellationToken
的乐观超时是最好的模拟。
等待任务。也可以使用延迟(5000,token)
来模拟响应取消的异步阻塞操作。@mountaintraveler这是真的,但它不会抛出取消异常。我认为这取决于预期的行为:安静取消或取消异常。
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
        };

    });
}