为什么具有无限循环的请求不会被 ColdFusion 请求超时杀死?



首先,我在 CF Admin 中将超时请求(秒(设置为20

然后我运行一个带有类似 while(true); 的行的 cfm

该页面将运行超过 20 秒,并且在我撰写本文时线程仍然处于活动状态。

下面是使用服务器监视器拍摄的快照

Thread  jrpp-3 request type - TEMPLATE REQUEST
*Template Path - D:ProjectsinfiniteLoop.cfm
*Request Parameters - {}
*Request Method - GET
*Client IP address - 127.0.0.1
*Thread elapsed time - 322659 milliseconds

这正常吗?? 这是 CF9.0.1.,开发人员版本。多实例设置,使用 JRun。

停止无限循环的唯一方法是重新启动 CF。

ColdFuison 中的请求超时不会按照您预期的方式运行。他们呈现的方式,你会想象有一个看门狗来检查你的请求已经运行了多长时间,并在请求超时时或之后不久杀死它。实际发生的是,只有当运行某些标记时,CF 才会检查请求的运行时间是否超过设置的限制。 <cfoutput> 是它检查的标签之一,这就是为什么您经常看到指向 cfoutput 的超时超出消息,即使您知道执行时间不会很长。

<cfsetting requesttimeout="5" enableCFoutputOnly="no" />
<!--- Looping with a condition <cfloop blamed --->
<cfset request.counter=0 />
<cfloop condition="true">
    <cfset sleep(1000) />
    <cfset request.counter=request.counter+1>
    <cflog file="timeout" text="#request.counter#">
    <cfif request.counter GT 8>
        <cfbreak>
    </cfif>
</cfloop>
<!--- Looping with an index, times out, naming CFLOOP as the offending tag --->
<cfloop index="foo" from="1" to="8">
    <cfset sleep(1000) />
</cfloop>
<!--- Looping with an index, times out, naming CFOUTPUT as the offending tag --->
<cfloop index="foo" from="1" to="8">
    <cfset sleep(1000) />
    <cfoutput>Hello</cfoutput>
</cfloop>

<!--- Same loop, but in script. No timeout warning at all --->
<cfscript>
for(foo=1;foo<=8;foo++){
    sleep(1000);
}
</cfscript>
<!--- Same loop, now with WriteOutput() called. Still no timeout --->
<cfscript>
for(foo=1;foo<=8;foo++){
    sleep(1000);
    writeoutput("tick...");
}
</cfscript>

上面的代码显示了请求超时的一些奇怪行为。正如 Mark Kruger 指出的那样,对外部资源的任何调用都意味着不检查超时,我猜只是执行你自己的逻辑的大块脚本也不会被检查,留下下一个输出语句被指责。

如果您需要跟踪代码滞后的位置以及超时消息指向错误的位置,我会使用日志记录或 jstack 在长时间运行的代码运行时从服务器获取堆栈跟踪。每隔几秒钟获取一些堆栈跟踪,然后通过 Samurai 运行日志文件以查找代码正在执行的操作。

不幸的是,当您知道 ColdFusion 中请求超时检查的约束时,您描述的是预期行为。 (当然,这不应该是预期的行为。

Charlie Arehart有一篇关于超时问题的长博客文章。 其中一个部分的标题是"CF 在下一个操作开始时检查时间,但遗憾的是只在某些标签上"。 不幸的是,cfscript不是其中之一,并且不会使用纯脚本代码检查超时。 但是,触发超时检查的标记之一是cfoutput并且有了这些知识,就可以使基于脚本的代码尊重请求超时。 但是,这是一个手动过程,因为您需要自己决定应该在哪里检查超时。

<cffunction name="cf_checkRequestTimeout" access="public" output="false" returntype="void" hint="Force CF to check if the request has timed out.">
    <!--- CF checks Request timeout on cfoutput tag use.  --->
    <cfoutput></cfoutput>
</cffunction>
<cfscript>
    for(foo=1;foo<=61;foo++){
        sleep(1000);
        cf_checkRequestTimeout();
    }
</cfscript>

生成的错误将归咎于第 4 行,这是误导性的,但堆栈跟踪将显示该函数是从第 11 行调用的,然后允许您知道哪位代码超时。 显然,该知识的粒度基于检查超时的频率。

cf_checkRequestTimeout(不是checkRequestTimeout,因为这是一个未记录的内部 CF 函数(也可以在 cfscript 之外调用,因此,例如,如果您有一个cfquery,您认为会导致超时问题,那么您可以将cf_checkRequestTimeout调用放在cfquery之后,并将超时错误放在应有的位置,而不是在代码执行中进一步向下。

我发现和亨利一样。 这是我的测试代码:

Before thread<br />
<cfthread action="run" name="t1">
    <cfloop condition="true">
        <cfparam name="count" default="0">
        <cfset sleep(3000)>
        <cflog file="cfthreadTest" text="Log entry #++count#">
    </cfloop>
</cfthread>
After thread<br />

我的请求超时在 CFAdmin 中设置为 20 秒,此线程现在已经运行了 15 分钟。 也就是说,线程不是"请求",所以我不确定我是否希望它遵守请求超时。 我找不到任何文档表明它应该尊重请求超时。 可是。。。有某种杀死线程的方法将是"方便的"。

我想这只是上下文中的"答案",我认为您的期望不正确,因为您希望它尊重请求超时。

最新更新