Performing Disaster Recovery After A ColdFusion Page Timeout Exception

Posted April 26, 2007 at 8:42 AM by Ben Nadel

Tags: ColdFusion

Previously, I blogged about how CFSetting updates the page timeout setting and does not actually start a new timeout. I had written about this in terms of disaster recovery. I can't find the conversation at this moment, but someone had raised a good point that in order to add time to the request timeout you would need to know how long the page had already been running (or you might set a value in seconds that has already passed).

I had suggested that you could use GetTickCount() in the Application.cfm/cfc file to get the start time of the page, then use that to get the run time of the page when it times out. This is lame because it requires modifying the Application.cfm/cfc file, which just doesn't feel right. Luckily, I just found out how to get the processing time of the page without modifying any other templates.

Using that technique, we can create a slightly more elegant disaster recovery model for ColdFusion request timeout exceptions:

  • <cffunction
  • name="KillTime"
  • access="public"
  • returntype="void"
  • output="false"
  • hint="I kill time for the given miliseconds.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="MS" type="numeric" required="true" />
  •  
  • <!--- Get start and end tick out values. --->
  • <cfset var intStart = GetTickCount() />
  • <cfset var intEnd = (intStart + ARGUMENTS.MS ) />
  •  
  • <!--- Loop until this time is killed. --->
  • <cfloop condition="(GetTickCount() LT intEnd)">
  •  
  • <!--- Just try to kill some processing time. --->
  • <cfset intStart = (intStart * Pi()) />
  •  
  • </cfloop>
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  •  
  •  
  • <!---
  • Set the current time out to be 2 seconds. We are
  • setting this intentionally low because we want the
  • page request to timeout.
  • --->
  • <cfsetting requesttimeout="2" />
  •  
  • <!--- Try to kill some time. --->
  • <cftry>
  •  
  • <!---
  • Here, we are killing time - 4 seconds to be
  • approximate. This will exceed the request time
  • out set above (2 seconds) and will throw an error.
  • --->
  • <cfset KillTime( 4000 ) />
  •  
  •  
  • <!---
  • The KillTime() method call has timed out (just
  • as we expected it to).
  • --->
  • <cfcatch>
  •  
  • <!---
  • Since we just caught an page timeout error, let's
  • set a new request time out that is high enough to
  • definitely let the page continue running. We HAVE
  • to do this because the line of code after this
  • requires too much processing time to run in the
  • 15-30 miliseconds that we have left to work with.
  • --->
  • <cfsetting requesttimeout="10" />
  •  
  •  
  • <!---
  • Now that we have some cushion time, let's use
  • the page and fusion context objects to get the
  • date/time stamp at which this page started
  • processing. Then, get the number of seconds
  • that that start date is smaller than the current
  • date/time stamp value.
  • --->
  • <cfset intRunTimeInSeconds = DateDiff(
  • "s",
  • GetPageContext().GetFusionContext().GetStartTime(),
  • Now()
  • ) />
  •  
  •  
  • <!---
  • Now that we know how long the page has been running,
  • let's create a new timeout setting with that time
  • plus whatever additional time we feel is necessary
  • to perform our disaster recovery. In this case, we
  • are going to add an additional 5 seconds. This will
  • override the "Safe" CFsetting we ran above.
  • --->
  • <cfsetting
  • requesttimeout="#(intRunTimeInSeconds + 5)#"
  • />
  •  
  •  
  • <!--------------------------------------->
  • <!--- Perform disaster recovery here. --->
  • <!--------------------------------------->
  •  
  • </cfcatch>
  •  
  • </cftry>
  •  
  •  
  • <!--- Get the new run time in seconds for the page. --->
  • <cfset intRunTimeInSeconds = DateDiff(
  • "s",
  • GetPageContext().GetFusionContext().GetStartTime(),
  • Now()
  • ) />
  •  
  •  
  • <!--- Output that run time. --->
  • <p>
  • The page has been processing for:
  • #intRunTimeInSeconds# Seconds.
  • </p>

Running the above code, we get:

The page has been processing for: 2 Seconds.

As you can see, even though we were caught in the middle of a ColdFusion request timeout, we were able to recover from it quite nicely.

The KillTime() method is used just to force a page timeout after a period of time. Once that happens, notice that we are immediately setting a static CFSetting request timeout setting. I don't like that we have to do this, but unfortunately, the DateDiff() that we are performing is too slow to execute fully in what little "wiggle" room we have (around 16 ms before the page actually dies). The idea of that first CFSetting tag is to have a timeout that we definitely will NOT exceed. I made it 10 seconds, but heck, you could make it 600 seconds. It won't matter since we then quickly override it with something more appropriate.

Once we know that we are safe to run, we can then easily figure out how long the page has been running and set a new timeout that is equal to the existing page run time plus whatever time we feel we are going to need to do CFLog or CFMail or what ever you need to do.




Reader Comments

Apr 26, 2007 at 9:08 AM // reply »
28 Comments

This is a very good idea, but doesn't onError usually run after a timeout? So couldn't you get yourself an email that way, too? What are the other instances where this could be of help?

I suppose that you could use this method to redirect the user to another page when certain operations time out, but I'd be interested in hearing about specific applications for this.


Apr 26, 2007 at 2:35 PM // reply »
11,238 Comments

@Tom,

The OnError() application even is policed by the same CFSettings as that the rest of the page processing. Therefore, if a CFQuery tag times out, OnError() will indeed fire, but if you try to do anything complex in the OnError(), it will fail.

This code above applies to all timeout exceptions as far as I know.


Apr 26, 2007 at 2:43 PM // reply »
5 Comments

Just an aside regarding your killtime function....you could also do a java sleep like so:

<cfset thread = CreateObject("java", "java.lang.Thread")>
<cfset thread.sleep(5000)>

As seen on
http://www.petefreitag.com/item/85.cfm


Apr 26, 2007 at 2:46 PM // reply »
11,238 Comments

Good thought, but as it turns out, sleeping a thread actually pauses the timeout:

http://www.bennadel.com/index.cfm?dax=blog:545.view


Apr 26, 2007 at 4:26 PM // reply »
1 Comments

I agree. Through a thread in java simpler


Apr 26, 2007 at 5:38 PM // reply »
11,238 Comments

I agree that a Java thread would be simpler...... if it worked ;)


Apr 23, 2009 at 11:58 AM // reply »
6 Comments

Great post!
You may want to wrap cfoutput tags around your final output on line 112 though or it won't output. :)


Don
Jul 8, 2009 at 4:46 PM // reply »
57 Comments

Why do I even bother googling problems like this? I should know just to come to your site. :D
This looks great. I am looping over a list and pulling data from another site and for whatever reason it sometimes hangs up. I was just catching the error and continuing the loop. But I'm thinking now is to limit the timeout so it doesn't hang for such a long time on those problem items and just moves on to the next one faster.


Jul 8, 2009 at 4:48 PM // reply »
11,238 Comments

@Don,

Always happy to be a second pair of eyes and inspiration in any problem :)


Don
Jul 15, 2009 at 2:57 PM // reply »
57 Comments

And what should happen now? A major client with a HUGE application that was originally "written" in 4.5 and I'm rewriting in 8 started throwing ugly timeout errors. It has worked fine all these years. I found that the original "coder" *cough cough* used cfsetting liberally throughout the application based on how long HE thought the query or whatever should take. So in one place he set the timeout to 3 seconds. That wasn't bad but he used Fusebox to do this in so there are layers of pages and on each call he put a different timeout so I had to drill down changing them all.
But what really irked me is that he just let it show the ugly error page. Now with what you showed here, they will fail nicely. Actually what I did was set it so it will reset the timeout and retry the query at the longer timeout. It does this until it reaches the absolute max timeout at which time it says "AW S**T" and stops trying and displays an error.


Jul 18, 2009 at 1:57 PM // reply »
11,238 Comments

@Don,

He set the request timeout to 3 seconds sometimes?? Ha ha ha, that just seems silly. Talk about getting anal with your timeout settings.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools