我有一份工作会定期做一些涉及ServerXmlHttpRquest
执行 HTTP 的工作POST
。该作业每 60 秒运行一次。
通常它运行没有问题。但是大约有五万分之一的机会(每两三个月)它会挂起:
IXMLHttpRequest http = new ServerXmlHttpRequest();
http.open("POST", deleteUrl, false, "", "");
http.send(stuffToDelete); <---hang
当它挂起时,甚至任务计划程序(如果运行时间超过 3 分钟,则启用了终止作业的选项)也无法结束任务。我必须连接到远程客户的网络,进入服务器,然后使用任务管理器来终止进程。
然后再过一三个月就好了。
最终我开始使用任务管理器创建一个进程转储,
所以我可以分析挂在哪里。在五次崩溃转储(过去 11 个月左右)之后,我得到了一致的画面:
ntdll.dll!_NtWaitForMultipleObjects@20()
KERNELBASE.dll!_WaitForMultipleObjectsEx@20()
user32.dll!MsgWaitForMultipleObjectsEx()
user32.dll!_MsgWaitForMultipleObjects@20()
urlmon.dll!CTransaction::CompleteOperation(int fNested) Line 2496
urlmon.dll!CTransaction::StartEx(IUri * pIUri, IInternetProtocolSink * pOInetProtSink, IInternetBindInfo * pOInetBindInfo, unsigned long grfOptions, unsigned long dwReserved) Line 4453 C++
urlmon.dll!CTransaction::Start(const wchar_t * pwzURL, IInternetProtocolSink * pOInetProtSink, IInternetBindInfo * pOInetBindInfo, unsigned long grfOptions, unsigned long dwReserved) Line 4515 C++
msxml3.dll!URLMONRequest::send()
msxml3.dll!XMLHttp::send()
Contoso.exe!FrobImporter.TFrobImporter.DeleteFrobs Line 971
Contoso.exe!FrobImporter.TFrobImporter.ImportCore Line 1583
Contoso.exe!FrobImporter.TFrobImporter.RunImport Line 1070
Contoso.exe!CommandLineProcessor.TCommandLineProcessor.HandleFrobImport Line 433
Contoso.exe!CommandLineProcessor.TCommandLineProcessor.CoreExecute Line 71
Contoso.exe!CommandLineProcessor.TCommandLineProcessor.Execute Line 84
Contoso.exe!Contoso.Contoso Line 167
kernel32.dll!@BaseThreadInitThunk@12()
ntdll.dll!__RtlUserThreadStart()
ntdll.dll!__RtlUserThreadStart@8()
所以我做了一个ServerXmlHttpRequest.send
,它永远不会回来。它会在那里呆几天(导致系统错过金融交易,直到周日晚上我接到电话说它坏了)。
除非有人知道如何调试代码,否则它没有任何帮助,但是转储时停滞线程中的寄存器是:
EAX 00000030
EBX 00000000
ECX 00000000
EDX 00000000
ESI 002CAC08
EDI 00000001
EIP 732A08A7
ESP 0018F684
EBP 0018F6C8
EFL 00000000
- 视窗服务器 2012 R2
- 微软 IIS/8.5
ServerXmlHttpRequest 的默认超时
您可以使用serverXmlHttpRequest.setTimeouts(...)
来配置四类超时:
- resolveTimeout:该值用于将主机名(例如“www.microsoft.com”)映射到 IP 地址;默认值是无限的,意味着没有超时。
- connectTimeout:一个长整数。该值用于与目标服务器建立通信套接字,默认超时值为 60 秒。
- sendTimeout:该值适用于将通信套接字上的单个请求数据包(如果有)发送到目标服务器。发送到服务器的大请求通常会被分解为多个数据包;发送超时适用于单独发送每个数据包。默认值为30 秒。
- receiveTimeout:该值适用于从目标服务器接收响应数据包。大响应将被分解成多个数据包;接收超时适用于从套接字中获取每个数据包。默认值为30 秒。
KB305053(决定保持连接打开的服务器将导致 serverXmlHttpRequest 等待连接关闭)似乎有可能是问题所在。但是 30 秒的默认超时会解决这个问题。
可能的解决方法 - 将自己添加到工作中
Windows 任务计划程序无法终止任务;即使启用了该选项来做。
我将研究使用 Windows 作业 API 将我的自我进程添加到作业中,并用于SetInformationJobObject
设置我的进程的时间限制:
将我的过程限制为三分钟的执行时间:
PerProcessUserTimeLimit
如果LimitFlags指定 JOB_OBJECT_LIMIT_PROCESS_TIME,则此成员是每个进程的用户模式执行时间限制,以 100 纳秒滴答为单位。否则,此成员将被忽略。系统会定期检查以确定与作业关联的每个进程是否累积了超过设置限制的用户模式时间。如果有,则终止该过程。
如果作业是嵌套的,则有效限制是作业链中最严格的限制。
虽然由于任务计划程序使用作业对象也限制任务的时间,但我也不希望作业对象可以限制作业。
编辑:作业对象不能通过进程时间来限制进程 - 只有用户时间。并且由于进程空闲等待一个对象,它不会累积任何用户时间——当然不值得三分钟。
奖金阅读
- ServerXMLHTTP GET 请求如何挂起? (
GET
, 不是POST
) - KB305053:当您发送 POST 请求时,ServerXMLHTTP 停止响应 (表示超时应该过期;我的没有)
- MS 论坛:oHttp.Send - 挂起 (
HEAD
,不是POST
) - MS 论坛:ASP 使用 MSXML2.ServerXMLHTTP 测试 SOAP WebService 发送挂起
- CC 到 MS 支持论坛