Serve Laurijssen
Serve Laurijssen

Reputation: 9733

Exception while running System.Threading.Tasks.Task

Consider the following code which uses basic Task library functionality with a CancellationTokenSource. It starts up a thread which fills a Dictionary with prices and reads the data from an SQL server db. The thread ends after about 10 minutes and every 2 hours it is fired up again, calling Cancel first in case the thread was still running.

private CancellationTokenSource mTokenSource = new CancellationTokenSource();

internal Prices(Dictionary<string, Dealer> dealers)
{
    mDealers = dealers;
    mTask = Task.Factory.StartNew
            (() => ReadPrices(mTokenSource.Token), mTokenSource.Token);
}

internal void Cancel() 
{
    mTokenSource.Cancel();
}
private void ReadPrices(CancellationToken ct) 
{
     using (SqlConnection connection = 
            new   SqlConnection(ConfigurationManager.AppSettings["DB"]))   
     {
         connection.Open();
         var dealerIds = from dealer in mDealers.Values 
                         where dealer.Id != null 
                         select dealer.Id;
         foreach (var dealerId in dealerIds) 
         {
             if (!ct.IsCancellationRequested)
             {
                 FillPrices(connection);
             }
             else
                break;
        }
    }
}

Now at some point the application crashes with the following exception in the event log.

Application: Engine.exe Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.AggregateException Stack: at System.Threading.Tasks.TaskExceptionHolder.Finalize()

It must have to do with the code here because the Tasks library isn't used anywhere else but I cant figure out what is wrong with the code. Does anyone have an idea what could be wrong here?

Upvotes: 10

Views: 6491

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062502

Tasks like to feel listened to. It sounds like something isn't happy. You do get a "last chance" to hear it out, though:

TaskScheduler.UnobservedTaskException += (sender, args) =>
{
    foreach (var ex in args.Exception.InnerExceptions)
    {
        Log(ex);
    }            
    args.SetObserved();
};

Note this isn't intended as the fix - it is intended to let you see what Task is exploding and with what error. The SetObserved() will prevent it killing your application. But the fix here is ideally:

  • don't let your tasks throw,
  • or make sure that you're there to check the status of the task later

It is quite possibly not happy with your cancellation detection. IIRC the preferred way to do that would be:

foreach(...) {
    if(ct.IsCancellationRequested) {
        // any cleanup etc
        ct.ThrowIfCancellationRequested();
    } 
    ...
}

or more simply if no cleanup is needed, just:

foreach(...) {
    ct.ThrowIfCancellationRequested();
    ...
}

Equally, it could just be a data access exception. There are any number of exceptions that can happen when talking to a database. Timeout, deadlock, cannot-connect, etc.

Upvotes: 19

Related Questions