任何方法来区分取消和超时 [英] Any way to differentiate Cancel and Timeout

查看:258
本文介绍了任何方法来区分取消和超时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些代码,通过使调用其他一些服务验证的一些数据。我都开始并行调用,然后等待,直到其中至少有一个结束。如果任何请求失败,我不关心其他调用的结果。

I have some code that is validating some data by making calls to a number of other services. I start all of the calls in parallel and then wait until at least one of them finishes. If any of the requests fail, I don't care about the result of the other calls.

我做与的HttpClient ,我已经通过了 HttpMessageHandler 中,做了一堆的日志记录。从本质上讲:

I make the calls with HttpClient and I have passed an HttpMessageHandler in that does a bunch of logging. Essentially:

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
    HttpResponseMessage response = null;

    try
    {
        response = await base.SendAsync(request, cancellationToken);
    }
    catch (OperationCanceledException ex)
    {
        LogTimeout(...);
        throw;
    }
    catch (Exception ex)
    {
        LogFailure(...);
        throw;
    }
    finally
    {
        LogComplete(...);
    }

    return response;
}

没有说我有跟的是当我取消请求麻烦的一部分。当我取消一个请求,我做是故意的,所以我不希望它得到记录为超时,但似乎没有要取消和一个真正超时任何区别。

No the part that I'm having trouble with is when I cancel the requests. When I cancel a request, I'm doing it on purpose, so I don't want it to get logged as a timeout, but there doesn't appear to be any difference between a cancellation and a real timeout.

反正有没有做到这一点?

Is there anyway to accomplish this?

编辑:我要澄清这一点,一点点。使得并行调用的服务传递CancellationTokens一个超时:

I need to clarify this, a little bit. The service making the calls in parallel is passing in CancellationTokens with a timeout:

var ct = new CancellationTokenSource(TimeSpan.FromSeconds(2));



因此,当服务器花费超过两秒钟响应,我得到一个 OperationCanceledException ,如果我手动取消标记源(说是因为另一台服务器在1秒钟后返回了一个错误),那么我仍然获得了 OperationCanceledException 。理想情况下,我将能够看看 CancellationToken.IsCancellationRequested 来确定它是否被取消,由于超时,而不是明确要求被取消,但现在看来,你得到相同的值,而不管的如何的就被取消了。

So when the server takes more than two seconds to respond, I get an OperationCanceledException, and if I manually cancel the token source (say because another server returned an error after 1 second), then I still get an OperationCanceledException. Ideally, I would be able to look at CancellationToken.IsCancellationRequested to determine if it was cancelled due to a timeout, as opposed to explicitly requested to be cancelled, but it appears that you get the same value regardless of how it was canceled.

推荐答案

如果要区分两个取消类型,则需要使用两个不同的取消标记。有没有别的办法。这是不是太硬,因为他们可以链接 - 只是有点尴尬

If you want to distinguish the two cancellation types, then you need to use two different cancellation tokens. There's no other way. This is not too hard since they can be linked - just a bit awkward.

写这IMO是超时代码移动到 SendAsync 方法,而不是调用方法:

The cleanest way to write this IMO is to move the timeout code into the SendAsync method instead of the calling method:

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
  using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
  {
    cts.CancelAfter(TimeSpan.FromSeconds(2));
    try
    {
      return await base.SendAsync(request, cancellationToken);
    }
    catch (OperationCanceledException ex)
    {
      if (cancellationToken.IsCancellationRequested)
        return null;
      LogTimeout(...);
      throw;
    }
    catch (Exception ex)
    {
      LogFailure(...);
      throw;
    }
    finally
    {
      LogComplete(...);
    }
  }
}

如果你不想移动超时代码到 SendAsync ,那么你需要做的日志记录方法之外,也。

If you don't want to move the timeout code into SendAsync, then you'll need to do the logging outside of that method, too.

这篇关于任何方法来区分取消和超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆