1
votes

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.

2
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
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
Throwing throw new AggregateException("FailureTask"); did not worked. Even catching only (base) Exception catches OperationCanceledException. - Gintaras
@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

2 Answers

2
votes

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());
        }
    }
1
votes

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

throw new AggregateException ("FailureTask");