Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

can I write a C# program that - when run as a scheduled task - detects when Task Scheduler tries to stop it

perhaps I'm misinterpreting this part of Windows' Task Scheduler UI, but the following options suggest (to me) that a program is first asked nicely to stop, and then forcefully quit when that fails:

if the running task does not end when requested...

from the deepest corners of my mind, I remembered that Windows applications can respond to requests to quit; with that in mind, I was able to google up AppDomain.CurrentDomain.ProcessExit. however, it appears that Task Scheduler's "stop the task..." and AppDomain.CurrentDomain.ProcessExit do not work together as I had hoped; here is an example program I threw together that does not work:

using System;
using System.Threading;
using System.Windows.Forms;

namespace GimmeJustASec
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.ProcessExit += new EventHandler(SuddenCleanup);

            while(true)
            {
                Thread.Sleep(1000);
            }
        }

        static void SuddenCleanup(object sender, EventArgs e)
        {
            MessageBox.Show("Hello!");
        }
    }
}

tl;dr my question is:

  1. can a program be written to respond to Task Scheduler stopping it? (or does Task Scheduler force-quit tasks in the rudest way possible?)
  2. if a program can be written in this way, how is the correct way to do so? (the way I tried is clearly not correct.)
  3. am I over-thinking all of this, and it would just be better to have the program time itself in a parallel thread? (perhaps with a max time set in app.config, or whatever.)

[edit] tried this variant, at Andrew Morton's request, with similar results:

using System;
using System.Threading;
using System.Windows.Forms;
using System.IO;

namespace GimmeJustASec
{
    class Program
    {
        private static StreamWriter _log;

        static void Main(string[] args)
        {
            _log = File.CreateText("GimmeJustASec.log");
            _log.AutoFlush = true;

            _log.WriteLine("Hello!");

            AppDomain.CurrentDomain.ProcessExit += new EventHandler(SuddenCleanup);

            while(true)
            {
                Thread.Sleep(1000);
            }
        }

        static void SuddenCleanup(object sender, EventArgs e)
        {
            _log.WriteLine("Goodbye!");
        }
    }
}

after Task Scheduler stops the task, the .log file contains "Hello!" but not "Goodbye!"

like image 916
Ben Avatar asked Aug 24 '17 17:08

Ben


People also ask

Can I write a B C in C?

Since C language does not support chaining assignment like a=b=c; each assignment operator (=) operates on two operands only.

Does a C+ exist?

C+ (grade), an academic grade. C++, a programming language. C with Classes, predecessor to the C++ programming language. ANSI C, a programming language (as opposed to K&R C)


1 Answers

The proper way to handle this is to assume your program can die suddenly and without any chance to run code whatsoever (because, you know, it can -- let's say the .NET runtime has a bug that triggers a crash) and detect this outside the program, so you can do the mailing/logging from there. If you can brook a delay, you can still do this from the program itself: detect an unclean shutdown when the task next runs and then notify. This is tons more reliable than attempting to do cleanup/signaling while the process is going down (for whatever reason). This is especially true for console applications (if you're using those) because exiting those normally doesn't even run any finalizers, unless you write code for it (AppDomain.ProcessExit and Console.CancelKeyPress aren't enough, you have to go all the way to SetConsoleCtrlHandler). All in all, this does not make me have much hope for a clean exit that isn't performed by the application itself.

This does not answer the original question of whether you can detect a request to stop issued by Task Scheduler, and if so, how. I've tried to establish how that works, but I failed: if I run a console application under Task Scheduler that refuses to exit, it will merrily keep on running, even if I've configured it to be terminated after 10 seconds or 1 minute. (You can't set timeouts this short from the interface, but you can from the command line.) I did not test if the minimum time supported by Task Scheduler, 1 hour, works. I've also not tested if things fare differently when using an actual schedule, rather than a manually triggered task. If you manually end a task, though, it defiinitely just calls TerminateProcess and doesn't give you any chance for a clean exit -- that alone should be some motivation to not put your code for signaling failure in the task itself.

like image 142
Jeroen Mostert Avatar answered Oct 04 '22 10:10

Jeroen Mostert