我正在使用一个策略来重试调用,以防由于某些原因导致调用失败。
AsyncRetryPolicy<HttpResponseMessage> GetPolicy() => Policy
.HandleResult<HttpResponseMessage>(a => a.StatusCode is HttpStatusCode.Poof or ...)
.WaitAndRetryAsync(stubborness, bideTime,
async (response, timespan, context) => { ... });
它的性能与GetAsync(...)
、PostAsync(...)
、PutAsync(...)
的预期一样。
using HttpResponseMessage response = await RetryPolicy
.ExecuteAsync(() => Client.PutAsync(url, content));
然而,它不能很好地与一般的SendAsync(...)
配合使用。如果调用失败,重试将启动,但随后崩溃,报告请求已被调度且无法重用的异常。在使用特定于动词的方法时,每次都会构造一个新的请求。使用一般的请求并传递自定义的、预先创建的请求,将使用它,因此会遇到麻烦。一个重要的细节是,我需要更改每个调用的头。
HttpRequestMessage request = new(HttpMethod.Put, new Uri(url));
request.Content = new StringContent(GetJson(code), Encoding.UTF8, "text/json");
request.Headers.Add("tenant", GetId(code));
using HttpResponseMessage response = await RetryPolicy
.ExecuteAsync(() => Client.SendAsync(request));
我尝试在使用专用方法的同时为每个调用提供特定于调用的头。这失败了,因为我没有发现任何过载。
我尝试过为每次调用更改客户端上的默认标头。由于在某些调用中使用了不一致性和错误的标头,所以失败了。
我已经尝试构建一个以ID作为默认标头的专用客户端。由于我最终会遇到大量不同的客户,这一切都失败了。
我已经尝试创建一个新的请求,并将其放入重试中。这失败了,因为我在WaitAndRetryAsync(...)
处理程序中找不到对HTTP上下文的引用,也找不到旧请求。
有办法绕着它跳舞吗
我看到一些文章表明,如果需要使用标头,SendAsync(...)
不是最合适的选择。然而,我固执得像鸭子一样,想确定这是否可能,而不仅仅是它是否顺利。
无论何时调用GetAsync
、PostAsync
或PutAsync
,无论何时调用它们,这些方法都会创建新的HttpRequestMessage
。
另一方面,无论何时调用SendAsync
,都需要指定一个HttpRequestMessage
作为参数。StackOverflow上有很多问题,详细说明了为什么不能多次重用HttpRequestMessage
。
这基本上就是你问题的根本原因。您希望在多次重试尝试中重复使用同一个HRM。
有几种解决方法:
- 在发起呼叫之前复制原始
HttpRequestMessage
(1( - 有一个方法,为每个
SendAsync
调用(1,2,3(创建一个新的HttpRequestMessage
- 将重试放入
DelegatingHandler
(1(- 顺便说一下,
AddPolicyHandler
就是这样做的(1,2,3(
- 顺便说一下,