Ian*_*oyd 6 windows winapi process reliability watchdog
我有一个定期运行的应用程序(这是一个计划任务).该任务每分钟启动一次,通常只需几秒钟即可完成业务,然后退出.
但是应用程序将会挂起,每80,000个机会(每两三个月)就有一个机会.根本原因是因为我们使用Microsoft ServerXmlHttpRequest组件来执行某些工作,有时它只是决定挂起.服务器 XmlHttpRequest优于XmlHttpRequest 的优点是不建议将后者用于重要场景,例如可靠性和安全性很重要(无人值守的服务器组件也是如此):
该
ServerXMLHTTP对象提供与对象类似的功能XMLHTTP.XMLHTTP但是,与ServerXMLHTTP对象不同,对象不依赖于WinInet控件来访问远程XML文档.ServerXMLHTTP使用新的HTTP客户端堆栈.专为服务器应用程序而设计,WinInet的这个服务器安全子集具有以下优势:
- 可靠性 - HTTP客户端堆栈提供更长的正常运行时间.WinInet功能对服务器应用程序并不重要,例如URL缓存,代理服务器的自动发现,HTTP/1.1分块,离线支持以及对Gopher和FTP协议的支持不包含在新的HTTP子集中.
- 安全性 - HTTP客户端堆栈不允许与其他用户的会话共享特定于用户的状态.ServerXMLHTTP提供对客户端证书的支持.
该作业正在作为计划任务运行.我需要继续定期运行任务; 杀死现有的进程,如果已经死了.
Windows任务计划程序确实有一个强制关闭运行时间过长的任务的选项:
这种方法的唯一缺点是它根本不起作用 - 它根本不能阻止任务.挂起的进程一直在运行.
鉴于我不能相信Microsoft ServerXmlHttpRequest不能任意锁定,并且任务调度程序无法终止计划任务,我需要一些方法来自己完成.
我尝试使用Job Objects API:
甲作业对象允许的处理组作为一个单元来管理.作业对象是可命名的,安全的,可共享的对象,用于控制与其关联的进程的属性.作业可以对与作业关联的每个进程强制执行限制,例如工作集大小,进程优先级和作业结束时间限制.
那个音符听起来就像我需要的那样:
作业可以对与作业关联的每个进程强制执行作业时间限制等限制.
这种方法的唯一缺点是它不起作用.工作不能对流程施加时间限制.他们只能对进程强加用户时间限制:
PerProcessUserTimeLimit
如果LimitFlags指定JOB_OBJECT_LIMIT_PROCESS_TIME,则此成员是每进程用户模式执行时间限制,以100纳秒为单位.
如果进程处于空闲状态(例如,作为ServerXmlHttpRequest坐在MsgWaitForSingleObject处),那么它将不会累积任何用户时间.我测试了它.我创建了一个有1秒时间限制的工作,并将自己的流程放入其中.只要我不在我的测试应用程序周围移动鼠标,它就会很高兴地坐在那里超过一秒钟.
鉴于我的主线程无限期被阻止,我能想象的唯一其他技术是另一个线程.我能想象的唯一解决方案是生成另一个将在我的三分钟内休眠的线程,然后是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);
}
Run Code Online (Sandbox Code Playgroud)
这很有效.唯一的缺点是这是一个坏主意.
谁能想到更好的东西?
编辑
现在我将实施一个
Contoso.exe /watchdog 180
Run Code Online (Sandbox Code Playgroud)
因此,该过程将在180秒后退出.这意味着持续时间是可配置的,或者可以在现场完全轻松删除.
我使用了在命令行上将特殊的WatchDog参数传递给我的进程的路线;
>Contoso.exe /watchdog 180
Run Code Online (Sandbox Code Playgroud)
在初始化期间,我检查该选项是否存在WatchDog,并在其后的整数秒内检查:
String s = Toolkit.FindCmdLineOption("watchdog", ["/", "-"]);
if (s <> "")
{
Int32 seconds = StrToIntDef(s, 0);
if (seconds > 0)
RunInThread(WatchdogThreadProc, Pointer(seconds));
}
Run Code Online (Sandbox Code Playgroud)
和我的线程程序:
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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
148 次 |
| 最近记录: |