Search code examples
c#.netexceptiontask-parallel-librarytask

Task swallows the exception thrown


In the method below, when an exception is thrown in the TRY block, it is being swallowed. How can I make it throw the exception so that it gets written to log in the catch block? The log writer works fine. Thanks!

public static bool MonitorQueueEmptyTask(string queueName, CancellationTokenSource tokenSource)
{
    try
    {
        Task<bool> task = Task.Factory.StartNew<bool>(() =>
        {
            while (!QueueManager.IsQueueEmpty(queueName))
            {
                if (tokenSource.IsCancellationRequested)
                {                            
                    break;
                }

                Thread.Sleep(5000);
                throw new Exception("Throwing an error!"); //THIS THROW IS SWALLOWED -- NO LOG WRITTEN ON CATCH
            };

            return true;

        }, tokenSource.Token);
    }
    catch (Exception ex)
    {   
        WriteExceptionToLog(ex.Stack); //it's not that this method doesn't work. it works fine.

        return false;
    }

    return true;
}

Solution

  • If you want to fire and forget, you can attach a continuation using ContinueWith. The current try-catch will not help you at all, as the exception is encapsulated inside the Task. If this is "fire and forget", than you can log the exception:

    public static Task MonitorQueueEmptyTask(
        string queueName, 
        CancellationTokenSource tokenSource)
    {
        return Task.Factory.StartNew<bool>(
            () => {
                while (!QueueManager.IsQueueEmpty(queueName))
                {
                    if (tokenSource.IsCancellationRequested)
                    {                            
                        break;
                    }
    
                    Thread.Sleep(5000);
                    throw new Exception("Throwing an error!");
                };
            }, 
            tokenSource.Token, 
            TaskCreationOptions.LongRunning)
        .ContinueWith(
            faultedTask => {
                WriteExceptionToLog(faultedTask.Exception); 
            }, 
            TaskContinuationOptions.OnlyOnFaulted); 
    }
    

    This, in turn, will not propagate the exception after it's thrown but will provide a mechanism to log the error.

    If you want the exception handled properly, you can register to TaskScheduler.UnobservedTaskException. Additionally, you can set ThrowUnobservedTaskExceptions enabled="true" in your configuration if you want unhandled exceptions to terminate your application.

    ContinueWith will consider the exception "handled" once you look at the task.Exception property.