【问题标题】:How to implement retry logic with Task Parallel Library(TPL) [duplicate]如何使用任务并行库(TPL)实现重试逻辑 [重复]
【发布时间】:2014-06-23 07:27:44
【问题描述】:

可能重复:
Retry a task multiple times based on user input in case of an exception in task

我正在寻找一种在 TPL 中实现重试逻辑的方法。我想要一个通用函数/类,它能够返回一个任务,该任务将执行给定的操作,并且在出现异常的情况下将重试该任务,直到给定的重试计数。我尝试使用 ContinueWith 并让回调在出现异常时创建一个新任务,但它似乎只适用于固定数量的重试。有什么建议吗?

    private static void Main()
    {
        Task<int> taskWithRetry = CreateTaskWithRetry(DoSometing, 10);
        taskWithRetry.Start();
        // ...

    }

    private static int DoSometing()
    {
        throw new NotImplementedException();
    }

    private static Task<T> CreateTaskWithRetry<T>(Func<T> action, int retryCount)
    {

    }

【问题讨论】:

    标签: c# .net task-parallel-library


    【解决方案1】:

    有什么理由对 TPL 做一些特别的事情吗?为什么不为Func&lt;T&gt; 本身做一个包装器?

    public static Func<T> Retry(Func<T> original, int retryCount)
    {
        return () =>
        {
            while (true)
            {
                try
                {
                    return original();
                }
                catch (Exception e)
                {
                    if (retryCount == 0)
                    {
                        throw;
                    }
                    // TODO: Logging
                    retryCount--;
                }
            }
        };
    }
    

    请注意,您可能希望添加 ShouldRetry(Exception) 方法以允许某些异常(例如取消)中止而无需重试。

    【讨论】:

    • 让每个动作(重试后)作为单独的任务运行不是更好吗?
    • @Amos:为什么?有什么优势?
    • 这类似于在任务 A 完成后使用 ContinueWith 执行任务 B,而不是让单个任务执行 A 然后 B。这样其他线程可以在多次重试后继续前进,而不是毕竟重试完成。
    • 您能否发布一个使用异步方法的 Retry 包装器的示例?
    • @SuperJMN:它不是为异步操作而设计的;我会采取不同的做法。
    【解决方案2】:
    private static Task<T> CreateTaskWithRetry<T>(Func<T> action, int retryCount)
    {
        Func<T> retryAction = () =>
        {
            int attemptNumber = 0;
            do
            {
                try
                {
                    attemptNumber++;
                    return action();
                }
                catch (Exception exception) // use your the exception that you need
                {
                    // log error if needed
                    if (attemptNumber == retryCount)
                        throw;
                }
            }
            while (attemptNumber < retryCount);
    
            return default(T);
        };
    
        return new Task<T>(retryAction);
    }
    

    【讨论】:

    • 我希望每次重试尝试执行单独的任务。这类似于在任务 A 完成后使用 ContinueWith 执行任务 B,而不是让单个任务执行 A 然后 B。这样其他线程可以在多次重试后继续前进,而不是在所有重试完成后。
    猜你喜欢
    • 2022-09-25
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-02
    • 1970-01-01
    相关资源
    最近更新 更多