【问题标题】:ASP.NET web API - System.Threading.Tasks.TaskCanceledException: A task was canceled dilemmaASP.NET Web API - System.Threading.Tasks.TaskCanceledException:任务被取消的困境
【发布时间】:2019-12-26 11:34:01
【问题描述】:

我有一个 asp.net 网络 API。 (net framework 4.6.1)我在我的一项操作中调用了第 3 方休息 API(产品)。在功能测试中,一切都按预期工作,没有问题。但是当我进行峰值测试时(比如说,100 个用户,10 秒的加速时间),在一些成功的响应之后,我得到了System.Threading.Tasks.TaskCanceledException: A task was canceled error。我用谷歌搜索并发现这可能是由于超时。我添加了TimeSpan.FromSeconds(600);,但仍然遇到同样的错误。

这就是我如何称呼这个第 3 方 API。异步调用有什么问题吗?你能看看我的代码吗?

public class UtilitiesTest
    {
        private static readonly HttpClient _httpClient = new HttpClient();


       //some not relevant code here

        public static async Task<HttpResponseMessage> CallRazer(GameRequest gameRequest, string url)
        {
            try
            {
                FormUrlEncodedContent content = null;

                if (url == "Product/")
                {
                    try
                    {
                        //some code here


                        //Timeout
                        _httpClient.Timeout = TimeSpan.FromSeconds(600);
                        //Call Game
                        var response = await _httpClient.PostAsync("https://test.com/" + url, content);
                        return response;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                    finally
                    {
                        content.Dispose();
                    }
                }
                else
                {
                    try
                    {
                        //some code here

                        //Call Game
                        var response = await _httpClient.PostAsync("https://test.com/" + url, content);
                        return response;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                    finally
                    {
                        content.Dispose();
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }


    }

这就是我对 Razer 的称呼:

private async Task<HttpResponseMessage> CallProducts()
        {
            //some code here

            #region Call Razer for products


            //**Call Razer**
            var response = await Utilities.CallRazer(products, "Product/");

            var htmlResponse = await response.Content.ReadAsStringAsync();
            var model = JsonConvert.DeserializeObject<ProductResponseDto>(htmlResponse);

           // some code here

            return response;
        }

另一个论坛的某个人建议我使用 HTTPWeb 请求而不是 Httpclient。所以我像下面这样更改了我的代码,我所有的麻烦都消失了。

//HTTPWebRequest
var request = (HttpWebRequest) WebRequest.Create("http://test.com" + url);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";

var keyValueContent = productRequest.ToKeyValue();
var formUrlEncodedContent = new FormUrlEncodedContent(keyValueContent);
var urlEncodedString = await formUrlEncodedContent.ReadAsStringAsync();

using (var streamWriter = new StreamWriter(await request.GetRequestStreamAsync()))
{
     streamWriter.Write(urlEncodedString);
}

HttpWebResponse httpResponse = (HttpWebResponse) (await request.GetResponseAsync());

response = new HttpResponseMessage
{
     StatusCode = httpResponse.StatusCode,
     Content = new StreamContent(httpResponse.GetResponseStream()),
};

return response;

【问题讨论】:

  • 任务取消是由于传递了取消令牌,我的理解是,如果您没有明确传递,那么取消令牌会附加在 3rd 方 API 中,这可能会由于各种逻辑原因触发任务取消。检查Task Status Enum
  • 还要检查Task Cacellation,这与由于异常导致的任务错误和Cancelling Async task after Timeout不同
  • 我没有传递取消令牌。当我对这种方法进行尖峰测试时会发生这种情况。起初,我得到了成功的响应,但过了一段时间我得到了错误。
  • 但第 3 方 API 可能会先检查,否则任务会出现故障而不被取消
  • @MrinalKamboj 谢谢,我会检查第 3 方。顺便说一句,我的代码怎么样?有cmets吗?

标签: c# asp.net-web-api async-await dotnet-httpclient


【解决方案1】:

如果 600 秒后仍然超时,那么您的网络服务就跟不上。

但是是的,超时会生成TaskCanceledException,这根本不直观。这实际上至少会在 .NET Core 中发生变化 (just fixed last week),但这对您没有帮助。

这是我用来重新抛出 TimeoutException 的代码。可能抛出TaskCanceledException 的唯一其他原因是,如果您传递了最终被取消的CancellationToken,但您没有。所以肯定是超时了。

} catch (TaskCanceledException) {
    //Could have been caused by cancellation or timeout if you used one.
    //If that was the case, rethrow.
    //cancellationToken.ThrowIfCancellationRequested();

    //HttpClient throws TaskCanceledException when the request times out. That's dumb.
    //Throw TimeoutException instead and say how long we waited.
    string time;
    if (_httpClient.Timeout.TotalHours > 1) {
        time = $"{_httpClient.Timeout.TotalHours:N1} hours";
    } else if (_httpClient.Timeout.TotalMinutes > 1) {
        time = $"{_httpClient.Timeout.TotalMinutes:N1} minutes";
    } else if (_httpClient.Timeout.TotalSeconds > 1) {
        time = $"{_httpClient.Timeout.TotalSeconds:N1} seconds";
    } else {
        time = $"{_httpClient.Timeout.TotalMilliseconds:N0} milliseconds";
    }
    throw new TimeoutException($"No response after waiting {time}.");
}

【讨论】:

  • 第三方服务是否有机会?
  • 你指的API?是的,这就是我的意思。它没有返回响应。你的代码很好。它可能无法跟上您的速度,或者他们有某种 DDoS 保护,由于您发送的请求过多而故意丢弃您的请求。问他们。
  • 我的 async/await 没问题,对吧?一直以来,我都试图在我的代码中找到错误是有原因的 :)
  • 是的,看起来不错。如果您有时会收到响应,那么您的代码就可以了。
  • 既然第三者还没有回应,我是否也应该检查我在云端的服务器?我不是服务器管理员,但如果你能告诉我要检查什么,我可以尝试做谷歌工程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多