如何将Polly重试应用于具有自定义标头的异步POST



我正在使用一个策略来重试调用,以防由于某些原因导致调用失败。

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(...)不是最合适的选择。然而,我固执得像鸭子一样,想确定这是否可能,而不仅仅是它是否顺利。

无论何时调用GetAsyncPostAsyncPutAsync,无论何时调用它们,这些方法都会创建新的HttpRequestMessage

另一方面,无论何时调用SendAsync,都需要指定一个HttpRequestMessage作为参数。StackOverflow上有很多问题,详细说明了为什么不能多次重用HttpRequestMessage

这基本上就是你问题的根本原因。您希望在多次重试尝试中重复使用同一个HRM。

有几种解决方法:

  • 在发起呼叫之前复制原始HttpRequestMessage(1(
  • 有一个方法,为每个SendAsync调用(1,2,3(创建一个新的HttpRequestMessage
  • 将重试放入DelegatingHandler(1(
    • 顺便说一下,AddPolicyHandler就是这样做的(1,2,3(

最新更新