并发任务失败x次后立即重新启动

本文关键字:重新启动 任务 失败 并发 | 更新日期: 2023-09-27 17:49:17

我有一个控制台应用程序,根据响应在我的数据库中进行HTTP查询和添加/更新产品。

我想到的方法是使用字典来存储产品ID和Task。然后我可以检查所有的任务结果并重新运行。

这是工作,但它打击我的效率低下。在所有任务完成之前,不会重新创建任务。如果它们立即重新启动,效率会更高,但我不知道该怎么做。而且,每次重试都涉及到对数据库的查询,因为只存储ID。

我做了一个小应用程序,显示我目前如何重试失败的请求。

有人能提出更有效的重试方法吗?

class Program
{
    private static void Main(string[] args)
    {
        HttpQuery m = new HttpQuery();
        var task = Task.Run(() => m.Start());
        Task.WaitAll(task);
        Console.WriteLine("Finished");
        Console.ReadLine();
    }
}
class HttpQuery
{
    public async Task Start()
    {
        // dictionary where key represent reference to something that needs to be processed and bool whether it has completed or not
        ConcurrentDictionary<int, Task<bool>> monitor = new ConcurrentDictionary<int, Task<bool>>();
        // start async tasks. 
        Console.WriteLine("starting first try");
        for (int i = 0; i < 1000; i++)
        {
            Console.Write(i+",");
            monitor[i] = this.Query(i);
        }
        // wait for completion
        await Task.WhenAll(monitor.Values.ToArray());
        Console.WriteLine();
        // start retries
        // number of retries per query
        int retries = 10;
        int count = 0;
        // check if max retries exceeded or all completed
        while (count < retries && monitor.Any(x => x.Value.Result == false))
        {
            // make list of numbers that failed
            List<int> retryList = monitor.Where(x => x.Value.Result == false).Select(x => x.Key).ToList();
            Console.WriteLine("starting try number: " + (count+1) + ", Processing: " + retryList.Count);
            // create list of tasks to wait for
            List<Task<bool>> toWait = new List<Task<bool>>();
            foreach (var i in retryList)
            {
                Console.Write(i + ",");
                monitor[i] = this.Query(i);
                toWait.Add(monitor[i]);
            }
            // wait for completion
            await Task.WhenAll(toWait.ToArray());
            Console.WriteLine();
            count++;
        }
        Console.WriteLine("ended");
        Console.ReadLine();
    }
    public async Task<bool> Query(int i)
    {
        // simulate a http request that may or may not fail
        Random r = new Random();
        int delay = i * r.Next(1, 10);
        await Task.Delay(delay);
        if (r.Next(0,2) == 1)
        {
            return true;
        }
        else
        {
            return false;
        }

    }
}

并发任务失败x次后立即重新启动

您可以创建另一个方法并包装所有这些丑陋的重试逻辑。所有丑陋的代码都消失了:)

public async Task Start()
{
    const int MaxNumberOfTries = 10;
    List<Task<bool>> tasks = new List<Task<bool>>();
    for (int i = 0; i < 1000; i++)
    {
        tasks.Add(this.QueryWithRetry(i, MaxNumberOfTries));
    }
    await Task.WhenAll(tasks);
}
public async Task<bool> QueryWithRetry(int i, int numOfTries)
{
    int tries = 0;
    bool result;
    do
    {
        result = await Query(i);
        tries++;
    } while (!result && tries < numOfTries);
    return result;
}