1
votes

I have a long running Console application (3 hrs) which I need to kill with an Exception in certain circumstances. The reason for killing this batch is that it is monitored by operators and controlled by an enterprise scheduler. An unhandled exception will alert them and its message used by the on-call support.

Ideally, I want a background thread running as a TPL Task to check for these database defined criteria, and if encountered throw an exception to fail the process. Throwing an exception in a Task does not kill the main thread. I have tried the following, running a ContinueWith Task on the main's scheduler but it does not affect main.

static void Main(string[] args)
{
    var mainThread = TaskScheduler.Current;
    var taskDb = new Task<bool>(RunDb, TaskCreationOptions.LongRunning);
    var taskHandle = taskDb.ContinueWith(b => Check(b.Result), mainThread);
    taskDb.Start();

    //do stuff
}

static bool RunDb()
{
    //check database in loop
    //if validation failed return false

    return false;
}

static void Check(bool successful)
{
    //check database in loop
    //if validation failed return false

    if(!successful)
       throw new Exception("batch failed for these reasons...");   
}

The only possible solution I've arrived at is modify a global property from within the ContinueWith action, and query this property from within the main thread, throwing an exception.

I've had a good look around the web and while there's plenty on cancelling threads from main, there's nothing about killing main from a background thread.

2

2 Answers

2
votes

You can use Environment.FailFast everywhere to shutdown your application with an exception. This works from a background thread as well:

Task.Run(() => Environment.FailFast("Fail", new Exception("batch failed for these reasons...")));

However, I think a more robust design would be to have a system wide CancellationToken that you can cancel from your task that brings down the entire application gracefully.

1
votes

Environment.Exit() is probably the easiest way. For example, the following program will exit after printing about 10 numbers, rather than the full 100.

public static void Main(string[] args)
{
    Task.Run(() =>
    {
        Thread.Sleep(1000);
        Console.Out.WriteLine("Something has gone terribly wrong!");
        System.Environment.Exit(1);
    });

    for (int i = 0; i < 100; i++)
    {
        Console.Out.WriteLine(i);
        Thread.Sleep(100);
    }
}