2

A class has async method MonitorAsync(), which starts a long-running parallel operation. I have a collection of these monitors; these are all kicked off as follows:

    internal async Task RunAsync()
    {
        var tasks = monitors.Select((p) => p.Value.MonitorAsync());
        await Task.WhenAll(tasks);
    }

If a monitor falls over, I need to know (basically I will run it up again). I've looked into ContinueWith and so on but when running a bunch of async tasks in parallel, how can I ensure I definitely know when one ends?

For context, RunAsync is basically the core of my application.

Mr. Boy
  • 60,845
  • 93
  • 320
  • 589
  • Related: [How to use Task.WhenAny and implement retry](https://stackoverflow.com/questions/43763982/how-to-use-task-whenany-and-implement-retry) – Theodor Zoulias May 15 '20 at 18:15

3 Answers3

3

If a monitor falls over, I need to know (basically I will run it up again).

The easiest way to do this is to define this logic in a separate method:

internal async Task RunAsync()
{
  var tasks = monitors.Select(p => MonitorAndRestart(p));
  await Task.WhenAll(tasks);

  async Task MonitorAndRestart(P p)
  {
    while (true)
    {
      try { await p.Value.MonitorAsync(); }
      catch { ... }
      p.Restart();
    }
  }
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
-2

If you want to know when one ends (and that does not affect the others), ContinueWith() could be the way.

Alternatively, how about WaitAny in a loop?

while(anyTaskUnfinished){
    await Task.WaitAny(tasks);
}
//Stuff you do after WhenAll() comes here

I am uncertain if you have to remove already finished Tasks. Or if it waits for any newly finishing.

Christopher
  • 9,634
  • 2
  • 17
  • 31
-2

You can try this:

If you do not want to call the Task.Wait method to wait for a task's completion, you can also retrieve the AggregateException exception from the task's Exception property

internal async Task RunAsync()
{
    var tasks = monitors.Select((p) => p.Value.MonitorAsync());
    try
    {
        await Task.WhenAll(tasks);
    }
    catch (Exception)
    {
        foreach (var task in tasks.Where(x => x.IsFaulted))
        foreach (var exception in task.Exception.InnerExceptions)
        {
            // Do Something
        }
    }
}

Reference: Exception handling (Task Parallel Library)

crgolden
  • 4,332
  • 1
  • 22
  • 40
  • This solution will delay the restarting of a failed monitor until all other monitors have been completed. Which is probably too late. – Theodor Zoulias May 15 '20 at 18:19