windows - 如果我跑得太久,我怎么能终止自己呢?

标签 windows winapi process watchdog reliability

我有一个定期运行的应用程序(这是一项计划任务)。该任务每分钟启动一次,通常只需几秒钟即可完成其业务,然后退出。

但应用程序挂起的几率约为 80,000 分之一(每两三个月)。根本原因是因为我们正在使用 Microsoft ServerXmlHttpRequest 组件来执行一些工作,并且 sometimes it just decides to hang . ServerXmlHttpRequest 优于 XmlHttpRequest 的优点是后者是 not recommended for important scenarios ,例如可靠性和安全性很重要的地方(无人值守的服务器组件也是如此):

The ServerXMLHTTP object offers functionality similar to that of the XMLHTTP object. Unlike XMLHTTP, however, the ServerXMLHTTP object does not rely on the WinInet control for HTTP access to remote XML documents. ServerXMLHTTP uses a new HTTP client stack. Designed for server applications, this server-safe subset of WinInet offers the following advantages:

  • Reliability — The HTTP client stack offers longer uptimes. WinInet features that are not critical for server applications, such as URL caching, auto-discovery of proxy servers, HTTP/1.1 chunking, offline support, and support for Gopher and FTP protocols are not included in the new HTTP subset.
  • Security — The HTTP client stack does not allow a user-specific state to be shared with another user's session. ServerXMLHTTP provides support for client certificates.

作业正在作为计划任务运行。我需要任务继续定期运行;如果现有进程已死,则将其杀死。

Windows 任务计划程序确实有一个选项可以强制关闭运行时间过长的任务:

enter image description here

该方法的唯一缺点是它根本行不通 - 它根本不会停止任务。挂起的进程继续运行。

鉴于我不能相信 Microsoft ServerXmlHttpRequest 不会任意锁定,并且任务计划程序无法终止计划任务,我需要一些方法来自己完成。

工作

我尝试研究使用 Job Objects API :

A job object allows groups of processes to be managed as a unit. Job objects are namable, securable, sharable objects that control attributes of the processes associated with them. A job can enforce limits such as working set size, process priority, and end-of-job time limit on each process that is associated with the job.

那个音符听起来正是我所需要的:

A job can enforce limits such as end-of-job time limit on each process that is associated with the job.

该方法的唯一缺点是它不起作用。工作不能对过程施加时间限制。他们只能强加 user time limit on a process :

PerProcessUserTimeLimit

If LimitFlags specifies JOB_OBJECT_LIMIT_PROCESS_TIME, this member is the per-process user-mode execution time limit, in 100-nanosecond ticks.

如果进程空闲(例如,像 ServerXmlHttpRequest 一样坐在 MsgWaitForSingleObject 上),那么它将不会累积任何用户时间。我测试了它。我创建了一个时间限制为 1 秒的作业,并将我的self 进程放入其中。只要我不在我的测试应用程序周围移动鼠标,它就会很高兴地在那里停留超过一秒钟。

看门狗线程

考虑到我的主线程被无限期阻塞,我能想到的唯一其他技术是另一个线程。我能想到的唯一解决方案是生成另一个线程,该线程将休眠三分钟,然后 ExitProcess :

Int32 watchdogTimeoutSeconds = FindCmdLineSwitch("watchdog", 0);
if (watchdogTimeoutSeconds > 0)
    Thread thread = new Thread(KillMeCallback, new IntPtr(watchdogTimeoutSeconds));

void KillMeCallback(IntPtr data)
{
   Int32 secondsUntilProcessIsExited = data.ToInt32();
   if (secondsUntilProcessIsExited <= 0) 
      return;

   Sleep(secondsUntilProcessIsExited*1000); //seconds --> milliseconds

   LogToEventLog(ExtractFilename(Application.ExeName), 
         "Watchdog fired after "+secondsUntilProcessIsExited.ToString()+" seconds. Process will be forcibly exited.", EVENTLOG_WARNING_TYPE, 999);

   ExitProcess(999);
}

那行得通。唯一的缺点是it's a bad idea .

谁能想到更好的办法?

编辑

现在我将实现一个

Contoso.exe /watchdog 180

因此进程将在 180 秒后退出。这意味着持续时间是可配置的,或者可以在现场轻松地完全删除。

最佳答案

我使用了在命令行上向我的进程传递一个特殊的 WatchDog 参数的路径;

>Contoso.exe /watchdog 180

在初始化过程中,我检查是否存在 WatchDog 选项,在它之后有一个整数秒数:

String s = Toolkit.FindCmdLineOption("watchdog", ["/", "-"]);
if (s <> "")
{
   Int32 seconds = StrToIntDef(s, 0);
   if (seconds > 0)
      RunInThread(WatchdogThreadProc, Pointer(seconds));
}

和我的线程程序:

void WatchdogProc(Pointer Data);
{
   Int32 secondsUntilProcessIsExited = Int32(Data);

   if (secondsUntilProcessIsExited <= 0)
      return;

   Sleep(secondsUntilProcessIsExited*1000); //seconds -> milliseconds

   LogToEventLog(ExtractFileName(ParamStr(0)), 
         Format("Watchdog fired after %d seconds. Process will be forcibly exited.", secondsUntilProcessIsExited), 
         EVENTLOG_WARNING_TYPE, 999);

   ExitProcess(2);
}

关于windows - 如果我跑得太久,我怎么能终止自己呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37054749/

相关文章:

PHP flock函数限制和txt缓存文件

windows - 升级 Windows 的 DOS 批处理文件

python - 使用转义空格反转字符串中的路径

windows - Git-bash Tab 补全 : "fatal: Not a git repository: ' . git'"(Windows)

windows - 获取进程总页面错误

c# - 如何使用C#依次运行两个进程?

C - 系统调用 - N 个子进程的数组分区 -

c++ - 多个文件的 Windows 上下文菜单 [C++]

windows - 查找 Windows 用户的 "true"应用程序数据文件夹?

c - 如何使用 C 和 WinAPI 将包含特殊字符的文本复制到剪贴板?