Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 重试上一个任务操作TPL_C#_Task Parallel Library - Fatal编程技术网

C# 重试上一个任务操作TPL

C# 重试上一个任务操作TPL,c#,task-parallel-library,C#,Task Parallel Library,我想实现一个重试任务,该任务执行上一个失败的任务操作并重复该操作 这就是我目前所拥有的。但是,它只是重复任务出错的事实,而不是再次实际启动任务的操作 public static async Task<T> Retry<T>(this Task<T> task, int retryCount, int delay, TaskCompletionSource<T> tcs = null) { if (tcs == null) {

我想实现一个重试任务,该任务执行上一个失败的任务操作并重复该操作

这就是我目前所拥有的。但是,它只是重复任务出错的事实,而不是再次实际启动任务的操作

public static async Task<T> Retry<T>(this Task<T> task, int retryCount, int delay, TaskCompletionSource<T> tcs = null)
{
    if (tcs == null)
    {
        tcs = new TaskCompletionSource<T>();
    }

    await task.ContinueWith(async _original =>
    {
        if (_original.IsFaulted)
        {
            if (retryCount == 0)
            {
                tcs.SetException(_original.Exception.InnerExceptions);
            }
            else
            {
                Console.WriteLine("Unhandled exception. Retrying...");

                await Task.Delay(delay).ContinueWith(async t =>
                {
                    await Retry(task, retryCount - 1, delay, tcs);
                });
            }
        }
        else
            tcs.SetResult(_original.Result);
    });
    return await tcs.Task;
}
理想情况下,我希望我的实现如下所示:

try
{
    await MakeFailure().Retry(5, 1000);
}
catch (Exception ex)
{
    Console.WriteLine("I had an exception");
}

这可能是不可能的,但在将代码重构为RetryFunc任务之前,我想确保有一个非常棒的库,您可以利用它而无需编写自己的代码。它被称为瞬态故障应用程序块。但我首先要评估一个名为

它的使用方式与上面的代码非常相似。下面是一个简单的例子:

using System;
using Microsoft.Practices.TransientFaultHandling;

namespace Stackoverflow
{
    class Program
    {
        internal class MyTransientErrorDetectionStrategy : ITransientErrorDetectionStrategy
        {
            public bool IsTransient(Exception ex)
            {
                return true;
            }
        }

        private static void Main(string[] args)
        {
            const int retryCount = 5;
            const int retryIntervalInSeconds = 1;

            // define the strategy for retrying
            var retryStrategy = new FixedInterval(
                retryCount,
                TimeSpan.FromSeconds(retryIntervalInSeconds));

            // define the policy 
            var retryPolicy =
                new RetryPolicy<MyTransientErrorDetectionStrategy>(retryStrategy);

            retryPolicy.Retrying += retryPolicy_Retrying;

            for (int i = 0; i < 50; i++)
            {
                // try this a few times just to illustrate

                try
                {
                    retryPolicy.ExecuteAction(SomeMethodThatCanSometimesFail);

                    // (the retry policy has async support as well)
                }
                catch (Exception)
                {
                    // if it got to this point, your retries were exhausted
                    // the original exception is rethrown
                    throw;
                }
            }

            Console.WriteLine("Press Enter to Exit");

            Console.ReadLine();
        }

        private static void SomeMethodThatCanSometimesFail()
        {
            var random = new Random().Next(1, 4);

            if (random == 2)
            {
                const string msg = "randomFailure";

                Console.WriteLine(msg);

                throw new Exception(msg);
            }
        }

        private static void retryPolicy_Retrying(object sender, RetryingEventArgs e)
        {
            Console.WriteLine("retrying");
        }
    }
}

有一个非常棒的库,您可以不用编写自己的代码就可以利用它。它被称为瞬态故障应用程序块。但我首先要评估一个名为

它的使用方式与上面的代码非常相似。下面是一个简单的例子:

using System;
using Microsoft.Practices.TransientFaultHandling;

namespace Stackoverflow
{
    class Program
    {
        internal class MyTransientErrorDetectionStrategy : ITransientErrorDetectionStrategy
        {
            public bool IsTransient(Exception ex)
            {
                return true;
            }
        }

        private static void Main(string[] args)
        {
            const int retryCount = 5;
            const int retryIntervalInSeconds = 1;

            // define the strategy for retrying
            var retryStrategy = new FixedInterval(
                retryCount,
                TimeSpan.FromSeconds(retryIntervalInSeconds));

            // define the policy 
            var retryPolicy =
                new RetryPolicy<MyTransientErrorDetectionStrategy>(retryStrategy);

            retryPolicy.Retrying += retryPolicy_Retrying;

            for (int i = 0; i < 50; i++)
            {
                // try this a few times just to illustrate

                try
                {
                    retryPolicy.ExecuteAction(SomeMethodThatCanSometimesFail);

                    // (the retry policy has async support as well)
                }
                catch (Exception)
                {
                    // if it got to this point, your retries were exhausted
                    // the original exception is rethrown
                    throw;
                }
            }

            Console.WriteLine("Press Enter to Exit");

            Console.ReadLine();
        }

        private static void SomeMethodThatCanSometimesFail()
        {
            var random = new Random().Next(1, 4);

            if (random == 2)
            {
                const string msg = "randomFailure";

                Console.WriteLine(msg);

                throw new Exception(msg);
            }
        }

        private static void retryPolicy_Retrying(object sender, RetryingEventArgs e)
        {
            Console.WriteLine("retrying");
        }
    }
}

你的问题是,一旦你有一个任务在飞行,它不能撤消或重试。您必须从Func开始才能重试

现在您可以直接使用TPL,但我建议您使用Microsoft的反应式框架来构建所需的功能。它比第三方物流强大得多

给定Func,这就是您需要的:

Func<Task<T>> taskFactory = ...
int retryCount = 5;
Task<T> retryingTask = Observable.FromAsync(taskFactory).Retry(retryCount).ToTask();
我用以下代码测试了这一点:

var i = 0;

Func<Task<int>> taskFactory = () => Task.Run(() =>
{
    if (i++ == 0)
        throw new Exception("Foo");
    return i;
});

int retryCount = 5;
Task<int> retryingTask = Observable.FromAsync(taskFactory).Retry(retryCount).ToTask();

Console.WriteLine(retryingTask.Result);

反应式框架可以让您做更多的事情——它是一个非常强大的库——但它确实使这项任务变得非常简单。您可以使用NuGet Rx Main来获取位。

您遇到的问题是,一旦任务处于运行状态,它就无法撤消或重试。您必须从Func开始才能重试

现在您可以直接使用TPL,但我建议您使用Microsoft的反应式框架来构建所需的功能。它比第三方物流强大得多

给定Func,这就是您需要的:

Func<Task<T>> taskFactory = ...
int retryCount = 5;
Task<T> retryingTask = Observable.FromAsync(taskFactory).Retry(retryCount).ToTask();
我用以下代码测试了这一点:

var i = 0;

Func<Task<int>> taskFactory = () => Task.Run(() =>
{
    if (i++ == 0)
        throw new Exception("Foo");
    return i;
});

int retryCount = 5;
Task<int> retryingTask = Observable.FromAsync(taskFactory).Retry(retryCount).ToTask();

Console.WriteLine(retryingTask.Result);
反应式框架可以让您做更多的事情——它是一个非常强大的库——但它确实使这项任务变得非常简单。您可以使用NuGet Rx Main来获取位

不完全反对。但它将代码流更改为我不喜欢的错误优先布局

考虑你的类型。任务表示异步操作。在异步世界中,任务表示已启动的异步操作。任务不是您可以重试的

另一方面,Func表示可以启动的异步操作。或者重新启动。这就是你需要解决的问题

使用适当的类型后,代码就简单明了了:

public static async Task<T> Retry<T>(Func<Task<T>> action, int retryCount, int delay)
{
  while (retryCount > 0)
  {
    try
    {
      return await action().ConfigureAwait(false);
    }
    catch (Exception ex)
    {
      await Task.Delay(delay).ConfigureAwait(false);
      --retryCount;
    }
  }
  return await action().ConfigureAwait(false);
}
像另一个回答者一样,我建议你使用一个真正为此而设计的库。和是两个很好的例子

不完全反对。但它将代码流更改为我不喜欢的错误优先布局

考虑你的类型。任务表示异步操作。在异步世界中,任务表示已启动的异步操作。任务不是您可以重试的

另一方面,Func表示可以启动的异步操作。或者重新启动。这就是你需要解决的问题

使用适当的类型后,代码就简单明了了:

public static async Task<T> Retry<T>(Func<Task<T>> action, int retryCount, int delay)
{
  while (retryCount > 0)
  {
    try
    {
      return await action().ConfigureAwait(false);
    }
    catch (Exception ex)
    {
      await Task.Delay(delay).ConfigureAwait(false);
      --retryCount;
    }
  }
  return await action().ConfigureAwait(false);
}

像另一个回答者一样,我建议你使用一个真正为此而设计的库。和是两个很好的例子。

您是否反对不将其作为扩展方法,并将方法签名更改为静态异步任务RetryFunc taskFactory、int retryCount等?这不是完全反对的。但它将代码流更改为错误优先的布局,我不喜欢Retryasync=>await MakeFailure,51000没有await MakeFailure干净。Retry51000不要试图攻击TPL来做它不适合做的事情。在上面创建一个抽象。你会反对不将其作为扩展方法,并将方法签名更改为static async Task RetryFunc taskFactory,int retryCount,…?这不是完全反对的。但它将代码流更改为错误优先的布局,我不喜欢Retryasync=>await MakeFailure,51000没有await MakeFailure干净。Retry51000不要试图攻击TPL来做它不适合做的事情。在其上创建一个抽象概念,而概念是合理的。我发现对于这个框架来说,API的冗长本质非常健谈。一个好的答案,尽管这个概念是正确的。我发现对于这个框架来说,API的冗长本质非常健谈。很好的答案尽管如此,在使用第三方物流时,我同意这是最好的答案。我希望一个任务能够保留一些关于它正在处理的操作的细节,但它似乎没有。@JonathanSheely:在现代异步/等待代码中,大多数任务甚至没有操作。在使用TPL时,我同意这是最好的
回答。我希望某个任务能够保留它正在处理的操作的一些细节,但它似乎没有。@JonathanSheely:在现代异步/等待代码中,大多数任务甚至没有操作。我已经在许多其他项目中使用Rx。这正是为什么我想知道是否有一种方法可以在TPL中只为一个重试例程进行一次简短的实现。@JonathanSheely-这很公平。比起第三方物流,我更喜欢Rx。我已经在我的许多其他项目中改用Rx。这正是为什么我想知道是否有一种方法可以在TPL中只为一个重试例程进行一次简短的实现。@JonathanSheely-这很公平。我更喜欢Rx而不是TPL。