1

I have a problem. I try to run multiple long running tasks. If one fails I wanna cancel all other tasks and get the failure exception. The example given below. I wanna catch AggregateException with Exception thrown by

 throw new Exception("FailureTask");

But instead of AggregateException I am catching OperationCanceledException, because I wanna cancel all other task.

    [TestMethod]
    public void TestParallelTaskCancelation()
    {
        var cancellationTokenSource = new CancellationTokenSource();
        Task[] tasks =
        {
            Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
            Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
            Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
            Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
            Task.Factory.StartNew(FailureTask, cancellationTokenSource, cancellationTokenSource.Token)
        };

        try
        {
            Task.WaitAll(tasks, cancellationTokenSource.Token);
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine(e.GetaAllMessages());
        }
        catch (AggregateException e)
        {
            Console.WriteLine(e.GetaAllMessages());
        }
    }

    private void DummyTask(object o)
    {
        var cancellationToken = (CancellationTokenSource)o;
        while (true)
        {
            Thread.Sleep(10000);
            if (cancellationToken.IsCancellationRequested)
            {
                cancellationToken.Token.ThrowIfCancellationRequested();
            }
        }
    }

    private void FailureTask(object o)
    {
        var cancellationToken = (CancellationTokenSource)o;

        var executionTask = Task.Factory.StartNew(() =>
        {
            Thread.Sleep(1000);
            throw new Exception("FailureTask");
        }, cancellationToken.Token);

        executionTask.ContinueWith(t =>
        {
            cancellationToken.Cancel(false);
            throw new Exception(t.Exception.GetaAllMessages());
        }, TaskContinuationOptions.OnlyOnFaulted);

        if (executionTask.Wait(10 * 1000, cancellationToken.Token)) return;
        //timeout !!!
        throw new Exception("The limit 'Max Seconds Per Query' has been exceeded!!!");
    }`

Please help.

Gintaras
  • 15
  • 2
  • 10
  • You throw a `Exception` which is the Base Class for all exceptions. `OperationCanceledException` and `AggregateException` are derived from `Exception`. Your Exception is never catched because you just catch the more specific exceptions. To catch a `AggregateException`, you have to throw a `AggregateException`. – Thomas Schneiter Dec 01 '16 at 14:13
  • What if two or more tasks fails simultaneously. Then which exception I will catch? What I have understood, that AggregateException should include cancellation exception for canceled tasks and exception for other tasks. – Gintaras Dec 01 '16 at 14:26
  • Throwing throw new AggregateException("FailureTask"); did not worked. Even catching only (base) Exception catches OperationCanceledException. – Gintaras Dec 01 '16 at 14:30
  • @ThomasSchneiter That’s not 100% percent correct. The 'OperationCanceledException' will be fire from the Taks.WaitAll, because it is cancel. And if you cancel the Task a AggregateException will be thrown. – ascholz Dec 01 '16 at 14:31

2 Answers2

2

This works for me

public static async void TestParallelTaskCancelation()
    {
        var cancellationTokenSource = new CancellationTokenSource();
        Task[] tasks =
        {
        Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
        Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
        Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
        Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
        Task.Factory.StartNew(FailureTask, cancellationTokenSource, cancellationTokenSource.Token)
        };

        try
        {
           await Task.WhenAll(tasks);
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine(e.ToString());
        }
        catch (AggregateException e)
        {
            Console.WriteLine(e.ToString());
        }
    }
Ive
  • 1,321
  • 2
  • 17
  • 25
1

You should use for throw AggregateException constructor instead of just Exception :

throw new AggregateException ("FailureTask");
Aleksandr Zolotov
  • 1,078
  • 3
  • 19
  • 32