【问题标题】:How do I use Polly for retries and transient fault handling of arbitrary "failure" conditions如何使用 Polly 对任意“失败”条件进行重试和瞬态故障处理
【发布时间】:2018-08-05 23:57:35
【问题描述】:

我想使用Polly 不是检查明显的“失败”,而是检查其他情况。具体来说,我想进行一个(异步)调用,例如httpClient.GetAsync(...),就这个问题而言,我知道它会成功——也就是说,在执行以下操作之后:

var response = await _myHttpRequestPolicy.ExecuteAsync(() => httpClient.GetAsync(uri));

response.IsSuccessStatusCode 将是 true

假设我做标准:

var content = await response.Content.ReadAsStringAsync();

content == { "Name":"Tom", "Age", 30", "ErrorCode":"12345" }

我希望我的策略逻辑根据响应的 ErrorCode 部分的内容(或不存在或存在)来执行。所以这只是我打的一个电话。

如何使用 Polly 做到这一点?

【问题讨论】:

  • 您可以创建自己的继承自 Policy 的类并在那里实现您自己的失败逻辑。并使用该策略类将您的 web api 调用包装在 Polly 下。
  • github.com/App-vNext/… 检查文档中的此链接,认为它描述了您要执行的操作。
  • @Max 我现在正在阅读它-我将在一些代码中尝试一下,但我不清楚我可以在没有 1 的情况下执行 1b(链接部分的位置) ...
  • @Howiecamp 你能显示你的策略配置的代码吗?
  • @Howiecamp Polly 有.HandleResult(...),您可以直接使用它,首先必须使用.Handle<SomeException>(...)。但是,如果结果条件依赖于通过额外的 async 调用检索响应,则单个 Polly 策略不涵盖这一点。请参阅this question and answer - 这是否也涵盖了您的问题?

标签: c# .net polly retrypolicy transient-failure


【解决方案1】:

您正在配置一个策略来保护 HttpClient GetAsync 方法,该方法返回 Task<HttpResponseMessage>。您想使用异步处理程序配置 Policy<HttpResponseMessage> 以使用此方法。

Policy<T>.HandleResult(Func<T, bool> filter) 允许您查看 HttpResponseMessage 并确定是否要处理该结果。

几个选项。一,您可以在 HandleResult 方法中找出反序列化/读取 HttpResponseMessage 的 json 有效负载。你只能得到一个Func<HttpResponseMessage, bool> 来工作。这需要同步发生,因为添加 async/await 会将返回类型更改为 Task。

其次,您可以在更高级别应用该策略。像 httpclient.GetAsync(uri) 一样获取响应,然后反序列化内容。也许有一个Policy<HttpResponseMessage> 包装httpclient 调用,一个Policy<MyAbstractApiResponse> 在反序列化后查找自定义错误代码?

请注意,API 错误确实应该由 HttpResponseMessage 上的 IsSuccessStatusCode 属性识别。您的 REST api(是您的吗?这是一个假设)应该设置适合错误的状态代码,而不仅仅是 200 和自定义响应属性。

相关延伸阅读:Check string content of response before retrying with Polly

更新:

class Consumer
{
  public void Test()
  {
    var apiResponse = Policy<IApiResponse>
      .HandleResult(resp => !string.IsNullOrWhiteSpace(resp.ErrorCode))
      // Setup Policy
      .ExecuteAsync(() => otherClassInstance.MakeApiCall());
  }
}

class OtherClass
{
  HttpClient httpClient = ...;
  public async Task<IApiResponse> MakeApiCall()
  {
    var response = Policy<HttpResponseMessage>
      .HandleResult(message => !message.IsSuccessStatusCode)
      // Setup Policy
      .ExecuteAsync(() => httpClient.GetAsync(url));

    var content = await response.ReadAsStringAsync();
    return new ApiResponse(content);
  }
}

在将它们放在一起时,我没有查看真实的方法名称或语法,因此它可能无法编译。希望您明白我要传达的想法,一个策略是从另一个策略中调用的。

【讨论】:

  • 我的理解是,如果我有一个Policy&lt;HttpResponseMessage&gt;,那么我的Policy&lt;HttpResponseMessage&gt;.HandleResult(Func&lt;T, bool&gt; filter) 中的过滤器表达式(谓词)必须检查返回的HttpResponseMessage 对象的某些属性,对吗?就我而言,我在响应正文中有任意文本。
  • 第二个问题 - 你说,“你正在配置一个策略来保护 HttpClient GetAsync 方法......”为了争论,假设我从等式中排除了这部分,换句话说,我要么处理或与波莉或不处理,无论如何。在那种情况下,我会提防 var content = await response.Content.ReadAsStringAsync(); 调用,而不是正确的??
  • 成功...我重新调整了思路——我明白自己哪里错了。我采取的方法是可以有 2 个策略 - 一个用于 httprequest 本身,一个用于检查返回数据的字符串内容。所以对于字符串内容(我希望存在或不存在给定字符串),我做了:var policy = Policy.HandleResult&lt;string&gt;(r =&gt; r == "bad response").Wait...,然后是:var body = await readAsStringAsyncPolicy.ExecuteAsync(() =&gt; response.Content.ReadAsStringAsync());,我很好。你觉得我的做法合适吗?
  • 我认为您的 2 策略方法绝对是正确的。无论您是串联还是包装,更多的是一个设计决定。我将编辑并添加一些伪代码来说明我如何处理这个问题。
  • 太好了,我很想看看。顺便说一句,我对成功的看法是错误的——我仍然在错误地思考这个问题。有点。由于我已经包装了 ReadAsStringAsync 操作,因此当它失败时,我需要做的是重新执行包装 http 调用的 original 策略。所以现在我有一些想法要做,因为我不知道该怎么做。
猜你喜欢
  • 2016-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多