【问题标题】:Why doesn't a request with an infinite loop get killed by ColdFusion request timeout?为什么带有无限循环的请求不会被 ColdFusion 请求超时杀死?
【发布时间】:2012-05-09 00:58:14
【问题描述】:

首先,我在 CF Admin 中将 Timeout Requests after (seconds) 设置为 20

然后我运行一个 cfm,其中包含 while(true); 之类的行

页面将运行超过 20 秒,并且在我写这篇文章时线程仍然存在。

以下是使用 Server Monitor 拍摄的快照

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

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

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

【问题讨论】:

  • Henry... 你在无限循环中做什么。 一些东西会抢占全局超时(数据库调用、ftp、需要外部资源的东西)。
  • 伙计们......这个问题没有提到CFTHREAD......不确定它来自哪里。
  • @MarkAKruger 我正在实施一些新的东西。代码仍然不稳定。我是用 CFScript 编写的,没想到最终被无限执行的代码不会被 CF 的请求超时杀死。
  • 嗯,我认为巴尼的回答可能是确定的。我正在询问一些 Adob​​e 人员,但共识似乎是肯定的 - cfscript 内部的循环不会响应全局超时值。如果你用标签格式重写你的循环,我猜你会得到你期望的超时。请记住,尽管本机调用(文件 I/O、DB 等)仍会受到此问题的影响。
  • 刚刚想到这个问题,CF共享托管会不会很麻烦?

标签: coldfusion infinite-loop


【解决方案1】:

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 运行日志文件以查找代码在做什么。

【讨论】:

  • 巴尼 - 这是一个很棒的答案。我喜欢它。感谢您的示例。看起来是博客文章和进一步调查的不错选择。
  • 我会加上答案,只是为了推荐武士。 (但总的来说也是一个很好的答案!)
  • 非常感谢您的调查!非常有趣/奇怪的结果。谁会想到,相同的循环,但在 cfscript 中,不会根据请求超时进行检查。这应该更正,或记录在某处......您是否也在使用 CF 9.0.1?也许我们应该用 CF7 或 8 来测试它,看看它是否确实是相同的结果。
  • @barnyr 你的调查让我想到.. 如果我以战略性的方式调用我的 cfscript,我仍然可以获得请求超时行为。
  • @Henry ColdFusion 在“执行”有限数量的标签之前检查请求超时。 cfoutput 是这些标签之一,也是大多数超时错误将cfoutput 报告为罪魁祸首的原因。因此,如果您的函数中只有一个 cfoutput,那么您只需让 CF 检查请求超时是否已过期,而几乎没有其他开销。将它放在循环中将使循环尊重请求超时。
【解决方案2】:

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

Charlie Arehart 写了一个很长的blog post 来讨论超时问题。一个部分的标题是“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 会导致超时问题,那么您可以将在cfquery 之后调用cf_checkRequestTimeout 并在应该出现的地方出现超时错误,而不是进一步执行代码。

【讨论】:

  • @Henry 让请求超时,并弄清楚发生了什么使请求超时是两件不同的事情。这个答案只是关于让超时发生。你说“哪个调用被抛出”是指循环的哪个迭代?您需要添加更多逻辑来解决这个问题。
【解决方案3】:

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

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 分钟。也就是说,线程不是“请求”,所以我不确定我是否希望它遵守请求超时。没有任何记录表明我可以发现它应该尊重请求超时。也就是说...有某种方式杀死线程会很“方便”。

我想这只是一个“答案”,我认为您的期望不正确,因为您希望它尊重请求超时。

【讨论】:

  • 感谢答案,但我不应该在标题中包含“线程”这个词,因为我根本没有使用 cfthread。问题已更新。
  • 好的,在那种情况下,你不能超越@barnyr 的回答。
猜你喜欢
  • 2011-07-31
  • 2014-10-10
  • 1970-01-01
  • 2021-04-12
  • 2022-01-14
  • 1970-01-01
  • 1970-01-01
  • 2016-03-29
相关资源
最近更新 更多