Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make an application crash when a Task throws an exception without waiting the finalizer

We are using Tasks in our .Net 4 (no async await available) application and sometimes they are used to launch 'Fire and Forget' operations like the following one:

private void Test()
{
    Task task = Task.Factory.StartNew(() =>
    {
        throw new ApplicationException("Test");
    });
}

We want this exception to crash the application without waiting the task (as otherwise it makes no sense to have it in a task, at least in our scenarios) and without waiting the finalizer as we want to shutdown the application when an unexpected error happens to avoid state corruptions (we are saving the state present when the exception happened).

My guess is that somehow we should work with a continuation task but that puts the continuation code inside another task that will not make the application crash so I'm blocked here.

Any help will be very appreciated

Edit: if switching to the ThreadPool the result is the expected one. The following code crashes the application:

ThreadPool.QueueUserWorkItem((c) =>
{
    throw new ApplicationException("Test");
});
like image 744
Ignacio Soler Garcia Avatar asked Jan 09 '15 08:01

Ignacio Soler Garcia


3 Answers

I finally found how to do it even when it is a bit complicated:

namespace ThreadExceptions
{
    using System;
    using System.Threading;
    using System.Threading.Tasks;

    public static class TaskExtensions
    {
        public static Task ObserveExceptions(this Task task)
        {
            return task.ContinueWith((t) =>
            {
                ThreadPool.QueueUserWorkItem((w) =>
                {
                    if (t.Exception != null)
                    {
                        foreach (Exception ex in t.Exception.InnerExceptions)
                        {
                            throw new TaskException(ex);
                        }
                    }
                });
            }, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.PreferFairness);
        }
    }
}

This will make the application crash without waiting for the task. That's was I was looking for.

like image 199
Ignacio Soler Garcia Avatar answered Oct 21 '22 06:10

Ignacio Soler Garcia


Try this solution using FailFast

This method terminates the process without running any active try/finally blocks or finalizers.

private void Test()
{
    Task task = Task.Factory.StartNew(() =>
    {
        Environment.FailFast("Test", new ApplicationException("Test"));
    });
}
like image 23
Mike Avatar answered Oct 21 '22 06:10

Mike


You could write your own Task class which wraps the various Task methods that you want to use, and add the exception handling to it.

For example:

public static class TaskWithExceptionHandling
{
    public static Task StartNew(Action action)
    {
        var task = Task.Factory.StartNew(action);

        task.ContinueWith(exceptionHandler, TaskContinuationOptions.OnlyOnFaulted);

        return task;
    }

    private static void exceptionHandler(Task task)
    {
        // Handle unhandled aggregate task exception from 'task.Exception' here.

        Console.WriteLine("Exception: " + task.Exception.GetBaseException().Message);
    }
}

Which you would substitute for the Task class like so:

Task task = TaskWithExceptionHandling.StartNew(() =>
{
    throw new InvalidOperationException("Test exception");
});

Console.ReadLine();
like image 1
Matthew Watson Avatar answered Oct 21 '22 05:10

Matthew Watson