我可以编写一个C#程序-当作为计划任务运行时-检测Task Scheduler何时尝试停止它

Ben*_*Ben 5 c# windows scheduled-tasks

可能是我误解了Windows的Task Scheduler UI的这一部分,但以下选项(对我来说)建议首先很好地要求程序停止,然后在失败时强制退出:

如果正在运行的任务没有在请求时结束...

从我最深的角落,我记得Windows应用程序可以响应退出请求。考虑到这一点,我得以谷歌搜索AppDomain.CurrentDomain.ProcessExit。但是,似乎任务计划程序的“停止任务...”并AppDomain.CurrentDomain.ProcessExit没有像我希望的那样协同工作;这是我放在一起无法使用的示例程序:

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!");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

tl; dr我的问题是:

  1. 可以编写程序来响应Task Scheduler停止它吗?(或者Task Scheduler是否以最粗鲁的方式强制退出任务?)
  2. 如果可以用这种方式编写程序,那么正确的方法是什么?(我尝试的方法显然是不正确的。)
  3. 我是否对所有这些都考虑得太多了,最好将程序时间本身放在并行线程中更好?(也许在app.config中设置了最大时间,或其他。)

[edit]应Andrew Morton的要求尝试了此变体,结果相似:

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!");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Task Scheduler停止任务后,.log文件将包含“ Hello!”。但不是“再见!”

Jer*_*ert 1

处理这个问题的正确方法是假设你的程序可能突然死掉,并且没有任何机会运行代码(因为,你知道,它可以 - 假设 .NET 运行时有一个触发崩溃的错误)并在外部检测到这一点程序,这样您就可以从那里进行邮件/日志记录。如果您可以容忍延迟,您仍然可以从程序本身执行此操作:在任务下次运行时检测到不正常的关闭,然后发出通知。这比在进程停止时(无论出于何种原因)尝试进行清理/发出信号要可靠得多。对于控制台应用程序来说尤其如此(如果您正在使用这些应用程序),因为退出这些应用程序通常甚至不会运行任何终结器,除非您为其编写代码(AppDomain.ProcessExit但这Console.CancelKeyPress还不够,您必须一路走到SetConsoleCtrlHandler)。总而言之,这并没有让我对应用程序本身不执行的干净退出抱有太大希望。

这并没有回答最初的问题:是否可以检测到任务计划程序发出的停止请求,如果可以,如何检测。我试图确定它是如何工作的,但我失败了:如果我在拒绝退出的任务计划程序下运行控制台应用程序,它将继续运行,即使我将其配置为在 10 秒或 1 秒后终止分钟。(您无法从界面设置这么短的超时,但可以从命令行设置。)我没有测试任务计划程序支持的最短时间(1 小时)是否有效。我也没有测试使用实际计划而不是手动触发任务时情况是否有所不同。但是,如果您手动结束任务,它肯定只会调用TerminateProcess,并且不会给您任何干净退出的机会——仅此一点就应该是不将用于指示失败的代码放入任务本身的动机。