Increase request timeout for stream in CFML

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

The process works fine on my development and staging servers, but of course the client is cheap and only pays for shared hosting, which is not as fast as my dev / staging boxes. As a result, PDF generation streams are synchronized.

The stream looks something like this:

  • The page is launched to create PDF files.
  • A query is made to determine which PDFs should be generated, and the loop triggers an application-scoped UDF call for each PDF that needs to be generated.
  • This UDF looks at the information for a given element, and then creates a stream to generate the PDF so that it works without letting the generation slow down the page.
  • The stream just uses CFDocument to create the PDF and save it to disk and then exits.

The threads do not join and nothing waits for either of them to complete. The page where UDF calls end in a few milliseconds; it is the threads themselves that fail.

Here's the code for UDFs (and creating streams):

<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 tried adding <cfsetting requestTimeout=240 />

to the top of the stream to try and extend the life ... no dice. I also got a little worried when I saw that the CFThread tag has a timeout parameter , but then realized that it only applies when connecting threads (action = join).

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

If anyone has any ideas on how to make these streams live longer, I will greatly appreciate them.

+1


source to share


5 answers


While this does not directly answer my original question about increasing the stream timeout, I was able to get the process to work (prevent timeouts) by improving the PDF generation times.

In accordance with LiveDocs a ColdFusion 8 added an attribute localUrl

to the tag CFDocument

, which indicates that the image files are located on the same physical machine, and should be included as local files, instead of doing HTTP-request for them.



Changing my code CFDocument

to the following caused the process to run fast enough that the threads would not log out.

<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>

      

+1


source


We use a generic 90 second timeout on our server (set in the CF admin), but use the instructions in the CFM files to override this setting where necessary. We also have a log of any request that is 30 seconds or more long, so we know which ones to optimize and / or need to override the request timeout (although the requested timeout would be obvious for other reasons, it's nice to have a list your slowest transactions in C: \ ColdFusion8 \ logs \ server.log).

For example, at the top of the CFM, which runs as a "night" task, I see:

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

      



I can tell you that it took 34,313 seconds when he ran last night. Obviously room for improvement in this process, but it ends a few hours before the start of the work day. If this requesttimeout was not set in the CFM file, the job will definitely exceed the 90 second mark.

In the past, we had longer tasks overriding this setting, I had to start at a much higher request timeout and watch for failures and re-jobs as we delayed everything. Ideally with good hardware, code, and good database structure, I would continue to tighten my CF admin timeout to the default CF8 of 30 seconds. Unfortunately my database structure and code have not yet reached this level.

+3


source


I don't think there is a way to extend the stream on a shared host where you don't have access to the cf admin. I think the cf admin constraint always overrides the cfsetting timeout value when it gets activated, so I think your hands are pretty much tied to this front.

My advice would be to change the strategy for generating all PDFs on the current page to instead run a different query for each PDF that needs to be generated. Not displaying the iframe while inelegant might be the simplest solution. You can simply output one iframe for each PDF that needs to be generated, and that way it should never time out as each individual PDF has to generate within the time limit set by the host.

+2


source


In case anyone finds this post and they are having problems where even simple pdfs like <cfdocument format="pdf">Hello world</cfdocument>

(minor content, no images) take minutes to render, check

Windows \ system32 \ drivers \ etc \ hosts

and make sure it points to itself

127.0.0.1 localhost

      

I had a properly functioning server and then all of a sudden the pdf data was pulled out until I set the CF Admin timeout to 5 minutes (?!?!?!). Some update (done I don't know who, maybe some network administrator / network monitor), modified the above file to a different intranet IP and DNS server name. I changed it and the PDFs resumed rendering at normal time responses.

0


source


-1


source







All Articles