我有一个定期运行的应用程序(这是一项计划任务)。该任务每分钟启动一次,通常只需几秒钟即可完成其业务,然后退出。
但应用程序挂起的几率约为 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 theXMLHTTP
object. UnlikeXMLHTTP
, however, theServerXMLHTTP
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 任务计划程序确实有一个选项可以强制关闭运行时间过长的任务:
该方法的唯一缺点是它根本行不通 - 它根本不会停止任务。挂起的进程继续运行。
鉴于我不能相信 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/