增加CFML中线程的请求超时

时间:2022-10-14 21:44:19

I have a web application that is generating hundreds of PDFs in batch, using ColdFusion 8 on a Windows/IIS server.

我有一个Web应用程序,使用Windows / IIS服务器上的ColdFusion 8批量生成数百个PDF。

The process runs fine on my development and staging servers, but of course the client is cheap and is only paying for shared hosting, which isn't as fast as my dev/staging boxes. As a result, PDF generation threads are timing out.

这个过程在我的开发和登台服务器上运行良好,但当然客户端很便宜并且只支付共享主机,这不如我的开发/暂存盒那么快。结果,PDF生成线程超时。

The flow is something like this:

流程是这样的:

  1. Page is run to generate PDFs.
  2. 运行页面以生成PDF。

  3. A query is run to determine which PDFs need to be generated, and a loop fires off an application-scoped UDF call for each PDF that will need to be generated.
  4. 运行查询以确定需要生成哪些PDF,并且循环会针对需要生成的每个PDF触发应用程序范围的UDF调用。

  5. That UDF looks up information for the given item, and then creates a thread for the PDF generation to work in, preventing generation from slowing down the page.
  6. UDF查找给定项目的信息,然后为PDF生成工作创建一个线程,防止生成减慢页面速度。

  7. The thread simply uses CFDocument to create a PDF and save it to disk, then terminates.
  8. 该线程只使用CFDocument创建PDF并将其保存到磁盘,然后终止。

Threads do not re-join, and nothing is waiting for any of them to finish. The page that makes the UDF calls finishes in a few milliseconds; it's the threads themselves that are timing out.

线程不重新加入,没有任何东西等待它们中的任何一个完成。进行UDF调用的页面在几毫秒内完成;这是线程本身的超时。

Here is the code for the UDF (and thread creation):

这是UDF(和线程创建)的代码:

<cffunction name="genTearSheet" output="false" returntype="void">
    <cfargument name="partId" type="numeric" required="true"/>
    <!--- saveLocation can be a relative or absolute path --->
    <cfargument name="saveLocation" type="string" required="true"/>
    <cfargument name="overwrite" type="boolean" required="false" default="true" />
    <cfset var local = structNew() />

    <!--- fix save location if we need to --->
    <cfif left(arguments.saveLocation, 1) eq "/">
        <cfset arguments.saveLocation = expandPath(arguments.saveLocation) />
    </cfif>

    <!--- get part info --->
    <cfif structKeyExists(application, "partGateway")>
        <cfset local.part = application.partGateway
        .getByAttributesQuery(partId: arguments.partId)/>
    <cfelse>
        <cfset local.part = createObject("component","com.admin.partGateway")
        .init(application.dsn).getByAttributesQuery(partId: arguments.partId)/>
    </cfif>

    <!--- define file name to be saved --->
    <cfif right(arguments.saveLocation, 4) neq ".pdf">
        <cfif right(arguments.saveLocation, 1) neq "/">
            <cfset arguments.saveLocation = arguments.saveLocation & "/" />
        </cfif>
        <cfset arguments.saveLocation = arguments.saveLocation & 
        "ts_#application.udf.sanitizePartNum(local.part.PartNum)#.pdf"/>
    </cfif>

    <!--- generate the new PDF in a thread so that page processing can continue --->
    <cfthread name="thread-genTearSheet-partid-#arguments.partId#" action="run" 
    filename="#arguments.saveLocation#" part="#local.part#" 
    overwrite="#arguments.overwrite#">
        <cfsetting requestTimeOut=240 />
        <cftry>
        <cfoutput>
        <cfdocument format="PDF" marginbottom="0.75" 
        filename="#attributes.fileName#" overwrite="#attributes.overwrite#">
            <cfdocumentitem type="footer">
                <center>
                <font face="Tahoma" color="black" size="7pt">
                pdf footer text here
                </font>
                </center>
            </cfdocumentitem>
            pdf body here
        </cfdocument>
        </cfoutput>
        <cfcatch>
        <cfset application.udf.errorEmail(application.errorEmail,
        "Error in threaded PDF save", cfcatch)/>
        </cfcatch>
        </cftry>
    </cfthread>
</cffunction>

As you can see, I've tried adding a <cfsetting requestTimeout=240 /> to the top of the thread to try and make it live longer... no dice. I also got a little excited when I saw that the CFThread tag has a timeout parameter, but then realized it only applies when joining threads (action=join).

正如你所看到的,我已经尝试在线程的顶部添加一个 来尝试让它活得更长......没有骰子。当我看到CFThread标签有一个超时参数时,我也有点兴奋,但后来意识到它只适用于加入线程(action = join)。

Changing the default timeout in ColdFusion Administrator is not an option, as this is a shared host.

在ColdFusion Administrator中更改默认超时不是一个选项,因为这是一个共享主机。

If anyone has any ideas on how to make these threads live longer, I would really appreciate them.

如果有人对如何让这些线程延长寿命有任何想法,我会非常感激他们。

4 个解决方案

#1


We use a 90 second overall timeout on our server (set in the CF administrator) but use statements in CFM files to override that setting where needed. We also have the server log any request that lasts 30 seconds or more so we know which ones need to be optimized and/or need the requesttimeout override (though a timed out request would be obvious for other reasons its nice to have a list of your slowest transactions in C:\ColdFusion8\logs\server.log).

我们在服务器上使用90秒的总超时(在CF管理员中设置),但使用CFM文件中的语句在需要时覆盖该设置。我们还有服务器记录任何持续30秒或更长时间的请求,因此我们知道哪些需要优化和/或需要requesttimeout覆盖(尽管由于其他原因显而易见的超时请求很高兴有一个列表C:\ ColdFusion8 \ logs \ server.log中的最慢事务。

For example at the top of a CFM that is run as an overnight task I see:

例如,在作为隔夜任务运行的CFM的顶部,我看到:

<cfsetting enablecfoutputonly="Yes" showdebugoutput="No" requesttimeout="80000">

I can tell you that the last night it ran it took 34,313 seconds to complete. Obviously room to improve that process but it finishes hours before the office day begins. If that requesttimeout parameter wasn't set in the CFM file that job would definitely timeout at the 90 second mark.

我可以告诉你,它运行的最后一晚需要34,313秒才能完成。显然有改进这个过程的空间,但它在办公室开始前几个小时就完成了。如果在CFM文件中没有设置该requesttimeout参数,那么作业肯定会在90秒标记处超时。

Before we had the longer tasks overriding that setting I had to start with a much higher request time out and watch the failures and rerun jobs as we tightened things up. Ideally with good hardware, code, and a good database structure I'd continue tightening my CF admin timeout down to the CF8 default of 30 seconds. Unfortunately my database structure and code is not up to that level yet.

在我们完成覆盖该设置的较长任务之前,我必须从更高的请求时间开始,观察失败并重新运行工作,因为我们收紧了工作。理想情况下,如果有良好的硬件,代码和良好的数据库结构,我会继续将CF管理超时时间缩短至CF8默认值30秒。不幸的是,我的数据库结构和代码尚未达到该级别。

#2


I don't think there is a way to make the thread live longer on a shared host where you don't have access to the cf admin. I think the cf admin limit always overrides the cfsetting requesttimeout value when it's activated, so I think your hands are pretty much tied on that front.

我不认为有一种方法可以让您在无法访问cf admin的共享主机上延长线程的使用寿命。我认为cf admin限制总是会在激活后覆盖cfsetting requesttimeout值,所以我认为你的手在这方面非常紧密。

My advice would be to change the strategy from creating all the PDFs within the current page to instead launching another request for each PDF that needs to be created. Non-displaying iframes while inelegant may be the simplest solution. You can simply output one iframe for each PDF that needs to be generated and that way it should never run into the timeout issue since each individual PDF should generate within the time limit set by the host.

我的建议是改变策略,从创建当前页面中的所有PDF,而不是为需要创建的每个PDF启动另一个请求。非显示的非显示iframe可能是最简单的解决方案。您只需为每个需要生成的PDF输出一个iframe,这样就不会遇到超时问题,因为每个PDF都应该在主机设置的时间限制内生成。

#3


While this doesn't directly answer my original question of increasing the timeout of a thread, I have been able to make the process work (prevent timeouts) by improving PDF generation time.

虽然这并没有直接回答我原来增加线程超时的问题,但我已经能够通过改进PDF生成时间来使进程工作(防止超时)。

According to the livedocs, ColdFusion 8 added a localUrl attribute to the CFDocument tag that indicates that image files are located on the same physical machine, and should be included as local files instead of making an HTTP request for them.

根据livesocs,ColdFusion 8将一个localUrl属性添加到CFDocument标记,该标记指示图像文件位于同一物理机器上,并且应该作为本地文件包含,而不是为它们发出HTTP请求。

Changing my CFDocument code to the following has made the process run fast enough that the threads don't time out.

将我的CFDocument代码更改为以下代码使得进程运行得足够快,线程不会超时。

<cfdocument format="PDF" marginbottom="0.75" 
filename="#attributes.fileName#" overwrite="#attributes.overwrite#" localUrl="yes">
    <cfdocumentitem type="footer">
        <center>
        <font face="Tahoma" color="black" size="7pt">
            pdf footer text here
        </font>
        </center>
    </cfdocumentitem>
    pdf body here
    <img src="images/foo/bar.gif"/>
</cfdocument>

#4


In case anyone finds this post and they are having trouble where even simple pdfs, e.g., <cfdocument format="pdf">Hello world</cfdocument> (negligible content, no images) are taking minutes to render, check your

如果有人发现这篇文章并且他们遇到麻烦甚至简单的pdf,例如 Hello world (可忽略的内容,没有图像)花费几分钟来渲染,请检查你的

Windows\system32\drivers\etc\hosts

server file and make sure it is pointing to itself

服务器文件,并确保它指向自己

127.0.0.1 localhost

I had a server functioning normally and then suddenly pdfs were timing out until I set the CF Admin timeout to 5 minutes (?!?!?!). Some update (done by I don't know who, probably some network security admin/monitor person) had modified the above file to some other intranet IP and the DNS server name. I changed it back and pdfs resumed rendering in normal time responses.

我有一台正常运行的服务器然后突然pdf超时,直到我将CF管理员超时设置为5分钟(?!?!?!)。一些更新(由我不知道是谁,可能是一些网络安全管理员/监控人员)将上述文件修改为其他一些内部网IP和DNS服务器名称。我改回来了,pdfs在正常时间响应中恢复渲染。

#1


We use a 90 second overall timeout on our server (set in the CF administrator) but use statements in CFM files to override that setting where needed. We also have the server log any request that lasts 30 seconds or more so we know which ones need to be optimized and/or need the requesttimeout override (though a timed out request would be obvious for other reasons its nice to have a list of your slowest transactions in C:\ColdFusion8\logs\server.log).

我们在服务器上使用90秒的总超时(在CF管理员中设置),但使用CFM文件中的语句在需要时覆盖该设置。我们还有服务器记录任何持续30秒或更长时间的请求,因此我们知道哪些需要优化和/或需要requesttimeout覆盖(尽管由于其他原因显而易见的超时请求很高兴有一个列表C:\ ColdFusion8 \ logs \ server.log中的最慢事务。

For example at the top of a CFM that is run as an overnight task I see:

例如,在作为隔夜任务运行的CFM的顶部,我看到:

<cfsetting enablecfoutputonly="Yes" showdebugoutput="No" requesttimeout="80000">

I can tell you that the last night it ran it took 34,313 seconds to complete. Obviously room to improve that process but it finishes hours before the office day begins. If that requesttimeout parameter wasn't set in the CFM file that job would definitely timeout at the 90 second mark.

我可以告诉你,它运行的最后一晚需要34,313秒才能完成。显然有改进这个过程的空间,但它在办公室开始前几个小时就完成了。如果在CFM文件中没有设置该requesttimeout参数,那么作业肯定会在90秒标记处超时。

Before we had the longer tasks overriding that setting I had to start with a much higher request time out and watch the failures and rerun jobs as we tightened things up. Ideally with good hardware, code, and a good database structure I'd continue tightening my CF admin timeout down to the CF8 default of 30 seconds. Unfortunately my database structure and code is not up to that level yet.

在我们完成覆盖该设置的较长任务之前,我必须从更高的请求时间开始,观察失败并重新运行工作,因为我们收紧了工作。理想情况下,如果有良好的硬件,代码和良好的数据库结构,我会继续将CF管理超时时间缩短至CF8默认值30秒。不幸的是,我的数据库结构和代码尚未达到该级别。

#2


I don't think there is a way to make the thread live longer on a shared host where you don't have access to the cf admin. I think the cf admin limit always overrides the cfsetting requesttimeout value when it's activated, so I think your hands are pretty much tied on that front.

我不认为有一种方法可以让您在无法访问cf admin的共享主机上延长线程的使用寿命。我认为cf admin限制总是会在激活后覆盖cfsetting requesttimeout值,所以我认为你的手在这方面非常紧密。

My advice would be to change the strategy from creating all the PDFs within the current page to instead launching another request for each PDF that needs to be created. Non-displaying iframes while inelegant may be the simplest solution. You can simply output one iframe for each PDF that needs to be generated and that way it should never run into the timeout issue since each individual PDF should generate within the time limit set by the host.

我的建议是改变策略,从创建当前页面中的所有PDF,而不是为需要创建的每个PDF启动另一个请求。非显示的非显示iframe可能是最简单的解决方案。您只需为每个需要生成的PDF输出一个iframe,这样就不会遇到超时问题,因为每个PDF都应该在主机设置的时间限制内生成。

#3


While this doesn't directly answer my original question of increasing the timeout of a thread, I have been able to make the process work (prevent timeouts) by improving PDF generation time.

虽然这并没有直接回答我原来增加线程超时的问题,但我已经能够通过改进PDF生成时间来使进程工作(防止超时)。

According to the livedocs, ColdFusion 8 added a localUrl attribute to the CFDocument tag that indicates that image files are located on the same physical machine, and should be included as local files instead of making an HTTP request for them.

根据livesocs,ColdFusion 8将一个localUrl属性添加到CFDocument标记,该标记指示图像文件位于同一物理机器上,并且应该作为本地文件包含,而不是为它们发出HTTP请求。

Changing my CFDocument code to the following has made the process run fast enough that the threads don't time out.

将我的CFDocument代码更改为以下代码使得进程运行得足够快,线程不会超时。

<cfdocument format="PDF" marginbottom="0.75" 
filename="#attributes.fileName#" overwrite="#attributes.overwrite#" localUrl="yes">
    <cfdocumentitem type="footer">
        <center>
        <font face="Tahoma" color="black" size="7pt">
            pdf footer text here
        </font>
        </center>
    </cfdocumentitem>
    pdf body here
    <img src="images/foo/bar.gif"/>
</cfdocument>

#4


In case anyone finds this post and they are having trouble where even simple pdfs, e.g., <cfdocument format="pdf">Hello world</cfdocument> (negligible content, no images) are taking minutes to render, check your

如果有人发现这篇文章并且他们遇到麻烦甚至简单的pdf,例如 Hello world (可忽略的内容,没有图像)花费几分钟来渲染,请检查你的

Windows\system32\drivers\etc\hosts

server file and make sure it is pointing to itself

服务器文件,并确保它指向自己

127.0.0.1 localhost

I had a server functioning normally and then suddenly pdfs were timing out until I set the CF Admin timeout to 5 minutes (?!?!?!). Some update (done by I don't know who, probably some network security admin/monitor person) had modified the above file to some other intranet IP and the DNS server name. I changed it back and pdfs resumed rendering in normal time responses.

我有一台正常运行的服务器然后突然pdf超时,直到我将CF管理员超时设置为5分钟(?!?!?!)。一些更新(由我不知道是谁,可能是一些网络安全管理员/监控人员)将上述文件修改为其他一些内部网IP和DNS服务器名称。我改回来了,pdfs在正常时间响应中恢复渲染。