Alex Rivera | Logout

TaskScheduler.UnobservedTaskException never gets called

Asked 2010-10-19T22:33:10.683
15

Based on my research, I have learned the following:

  1. TaskScheduler.UnobservedTaskException must wait for the task to be garbage collected before that task's unobserved exception will bubble up to the UnobservedTaskException event.
  2. If you're using Task.Wait(), it'll never get called anyway, because you're blocking on an impending result from the Task, hence the exception will be thrown on Task.Wait() rather than bubble up to the UnobservedException event.
  3. Calling GC.Collect() manually is generally a bad idea unless you know exactly what you're doing, hence it's good in this case for confirming things, but not as a proper solution to the issue.

The Problem

If my application exits before the garbage collector kicks in, I absolutely 100% cannot get my UnobservedTaskException event to fire.

Note the following code:

class Program
{
    static void Main(string[] args)
    {
        TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;

        Task.Factory.StartNew(() =>
        {
            Console.WriteLine("Task started.");
            throw new Exception("Test Exception");
        });

        Thread.Sleep(1000);
        //GC.Collect();
        //GC.WaitForPendingFinalizers();
    }

    static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
    {
        File.WriteAllText(@"C:\data\TestException.txt", e.Exception.ToString());
        Console.WriteLine("UNOBSERVED EXCEPTION");
    }
}

No exception file is written and nothing is written to the console. 10-15 minutes and more can go by after the application exits and still I see no evidence that my application's remains were garbage collected. You might ask, well why not just collect on exit? Well, my real world scenario is that my exc

Edit
Report

1 Answer

10

To me, TaskScheduler.UnobservedTaskException at first gives a very wrong sense of security. It's really not worth much if it depends on Garbage Collection.

I found the following solution, taken from this msdn article, to be much more reliable. It basically executes the continuation block (where you log the exception) only if there were unhandled exceptions in task1, and does not block UI execution.

You might also want to flatten nested AggregateExceptions and perhaps create a extension method, as Reed Copsey depicted here.

var task1 = Task.Factory.StartNew(() =>
{
    throw new MyCustomException("Task1 faulted.");
})
.ContinueWith((t) =>
{
    Console.WriteLine("I have observed a {0}",
        t.Exception.InnerException.GetType().Name);
},
TaskContinuationOptions.OnlyOnFaulted);
answered 2012-10-22T08:21:39.617

Your Answer