【问题标题】:c#: Restart an Async task after certain time passes before completionc#:在完成之前经过一定时间后重新启动异步任务
【发布时间】:2020-09-14 17:40:20
【问题描述】:

所以,我一直在开发一个使用 REST API 请求的应用程序,但是,由于某种原因,API 随机无响应(有时它会在 3 秒内给出响应,有时请求会花费很长时间以至于它抛出a timeOutexception) 所以每当我使用呼叫时,如果在一定时间内没有检索到响应,我会使用此代码重新启动呼叫:

bool taskCompletion = false;
        while(taskCompletion == false)
        {
            try
            {
                using (CancellationTokenSource cts = new CancellationTokenSource())
                {
                    cts.CancelAfter(timeSpan);
                    await task(cts.Token);
                    taskCompletion = true;
                }
            }
            catch (OperationCanceledException)
            {
                taskCompletion = false;
            }
        }

我的 API 请求之一如下:

 public static async Task<Result> task(CancellationToken ct)
    {
        string Url = baseurl
        ApiHelper instance = new ApiHelper();

        using (HttpResponseMessage response = await instance.ApiClient.GetAsync(Url, ct))
        {
            if (response.IsSuccessStatusCode)
            {
                var x = await response.Content.ReadAsStringAsync();
                var result = JsonConvert.DeserializeObject<ResultL>(x);
                if (result.result.Count() != 0)
                    return result.result[0];
                else
                    return null;
            }
            return null;
        }
    }

我不认为每次对代码使用的每个不同 API 请求都使用 try-catch 是最好的解决方案,我们将非常感谢任何有关如何改进我的代码的帮助!

【问题讨论】:

    标签: c# rest asynchronous servicenow


    【解决方案1】:

    您是否考虑过使用容错库? .net 的一个例子是 Polly。 https://github.com/App-vNext/Polly

    这很有帮助,因为您可以轻松配置重试计数或超时以及特定类型异常的回退逻辑。

    Scott Hanselman 对此也有一篇非常有帮助的文章: https://www.hanselman.com/blog/AddingResilienceAndTransientFaultHandlingToYourNETCoreHttpClientWithPolly.aspx

    我以前使用过它,它使我的代码超级干净且易于管理,因为所有策略都在一个地方,而不是 http 响应处理程序的一部分。如果需要,您还可以为每个不同的 http 请求者或客户端制定单独的策略。

    【讨论】:

    • 太棒了!看了这篇文章后,似乎正是我需要的,我会尽快实现它,谢谢!
    【解决方案2】:

    这个问题的全部前提是,一个已经变得无响应的异步操作仍然会通过提供的CancellationToken 响应取消请求。我对这个假设在现实生活中的适用性有点怀疑,但无论如何这里有一个AwaitCancelRetry 方法,如果需要太长时间才能完成,它会自动取消并重复异步操作:

    public static async Task<T> AwaitCancelRetry<T>(
        Func<CancellationToken, Task<T>> function, TimeSpan timeout,
        int maxAttempts, CancellationToken externalToken = default)
    {
        for (int i = 0; i < maxAttempts; i++)
        {
            using (var cts = CancellationTokenSource
                .CreateLinkedTokenSource(externalToken, default))
            {
                cts.CancelAfter(timeout);
                try
                {
                    return await function(cts.Token); // Continue on captured context
                }
                catch (OperationCanceledException ex)
                    when (ex.CancellationToken == cts.Token
                        && !externalToken.IsCancellationRequested)
                {
                    continue;
                }
            }
        }
        throw new TimeoutException();
    }
    
    // Non generic version
    public static Task AwaitCancelRetry(
        Func<CancellationToken, Task> function, TimeSpan timeout,
        int maxAttempts, CancellationToken externalToken = default)
        => AwaitCancelRetry<object>(
            async ct => { await function(ct).ConfigureAwait(false); return null; },
            timeout, maxAttempts, externalToken);
    

    使用示例:

    private static HttpClient _httpClient;
    
    public static Task<string> GetDataAsync(string url, CancellationToken token)
    {
        return AwaitCancelRetry(async ct =>
        {
            using (HttpResponseMessage response = await _httpClient.GetAsync(url, ct))
            {
                if (response.IsSuccessStatusCode)
                {
                    return await response.Content.ReadAsStringAsync();
                }
                return null;
            }
        }, TimeSpan.FromSeconds(10), maxAttempts: 3, token);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-22
      • 2016-07-16
      • 2017-08-07
      • 1970-01-01
      • 1970-01-01
      • 2021-10-15
      相关资源
      最近更新 更多