HttpClient Polly超时策略

问题描述

获取请求等待的时间超过timeoutPolicy超时。

  • 有人知道为什么会这样吗?
  • 为什么请求不会在30毫秒后超时?
var timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(30),TimeoutStrategy.Optimistic);
var watch = new Stopwatch();
try
{
    watch.Start();
    var httpResponse = await timeoutPolicy.ExecuteAsync(
        async ct => await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get,"https://google.com"),ct),CancellationToken.None
    );
    watch.Stop();
    Console.WriteLine("request took " + watch.ElapsedMilliseconds);
}
catch (Exception e)
{
    watch.Stop();
    Console.WriteLine("timeout took " + watch.ElapsedMilliseconds);
    Console.WriteLine(e.Message);
}

解决方法

我想我已经玩够了,知道发生了什么,所以我有信心现在可以回答这个问题。

当您使用async的Polly策略调用TimeoutStrategy.Optimistic任务时,您传入的是CancellationToken并实质上相信将调用CancellationToken来结束任务超时情况。

TimeoutStrategy.Pesimistic策略的行为不同,该策略旨在终止不通过CancellationToken进行回调的同步任务。

虽然您的主执行线程没有被在另一个线程上运行的异步任务阻止,但重要的是要记住该任务确实能够阻止它自己的线程。

例如,如果异步任务要调用Thread.Sleep(1000),则该线程的线程将被阻塞一秒钟。这反过来意味着CancellationToken不能在块的持续时间内被调用。

在这种情况下,我认为长时间运行的操作(例如,首次查找主机名的DNS记录)或正在发生的其他任何阻止操作实际上将阻止线程90ms。

这样,即使任务知道它需要在30ms标记处中止,它也需要等待线程可用,然后才能实际调用取消,直到大约90ms左右才会发生取消

对于每个域解析来说,这种返回超时的延迟似乎只是第一次出现,因此我认为这与名称服务器缓存和DNS解析有关,因为后续调用似乎可以更有效地兑现超时。尽管断言任何直接的根本原因在很大程度上是猜测。