Skip to main content
Ben Nadel at cf.Objective() 2011 (Minneapolis, MN) with: Alec Irwin
Ben Nadel at cf.Objective() 2011 (Minneapolis, MN) with: Alec Irwin

Dealing With RequestTimeOut And The OnError Application Event Method (Help Me)

By
Published in Comments (14)

I was reading over on Dan Vega's blog this morning about request time outs when I came up with a question: How do you deal with handling time outs when your OnError() event method takes a bit of time to run? Take this simple ColdFusion example as demonstration.

First, I set up a very simple Application.cfc ColdFusion component:

<cfcomponent>

	<!--- Set up global page processing. --->
	<cfsetting
		requesttimeout="5"
		showdebugoutput="false"
		/>


	<cffunction
		name="OnError"
		access="public"
		returntype="void"
		output="true">

		<p>
			You have errored out.
		</p>

		<p>
			Error: #ARGUMENTS[ 1 ].Message#
		</p>

	</cffunction>

</cfcomponent>

This Application.cfc merely sets up the request time out for page requests and defines an OnError() event method. Then, I set up a simple page that was designed to run longer than the request time out:

<!---
	Set up a bunch of CFHttp calls to force the page to
	run longer than the set request time out.
--->
<cfhttp url="http://www.google.com?q=#Rand()#" />
<cfhttp url="http://www.yahoo.com?q=#Rand()#" />
<cfhttp url="http://www.cnn.com?q=#Rand()#" />
<cfhttp url="http://www.searchgalleries.com?q=#Rand()#" />
<cfhttp url="http://www.espn.com?q=#Rand()#" />
<cfhttp url="http://www.houseoffusion.com?q=#Rand()#" />
<cfhttp url="http://www.fullasagoog.com?q=#Rand()#" />
<cfhttp url="http://www.ask.com?q=#Rand()#" />
<cfhttp url="http://www.cnet.com?q=#Rand()#" />

<!--- Success! --->
Done grabbing content.

Since I have to get and grab the content from each of the URLs above, this should take more than the allowed five second time out. And, indeed, running that page does throw a time-out error:

You have errored out.

Error: The request has exceeded the allowable time limit Tag: cfhttp

So far, the OnError() event method works fine. But what happens when the OnError() event is not quite so simple. Let's update the event method so that it gives us more information:

<cffunction
	name="OnError"
	access="public"
	returntype="void"
	output="true">

	<p>
		You have errored out.
	</p>

	<p>
		Error: #ARGUMENTS[ 1 ].Message#
	</p>

	<!--- Dump out the error arguments. --->
	<cfdump
		var="#ARGUMENTS[ 1 ]#"
		top="1"
		/>

</cffunction>

Now, in addition to dumping out the error message, we are going to dump out the top level values of all argument variables. If we run the page again, we now get this error:

You have errored out.

Error: The request has exceeded the allowable time limit Tag: cfhttp

The web site you are accessing has experienced an unexpected error. Please contact the website administrator.

The request has exceeded the allowable time limit Tag: cfoutput

The error occurred in D:\...\Application.cfc: line 26

24 :
25 : <!--- Dump out the arguments. --->
26 : <cfdump var="#ARGUMENTS[ 1 ]#" top="1" />
27 :
28 : </cffunction>

As you can see, the OnError() event method is still catching the CFHttp time out, but by that time, the OnError() event method has no "request time out" left for itself to process anything.

I run into this problem a lot with CFQuery and CFExecute. Does anyway have a way to handle this more elegantly? Perhaps OnError() is not the right way to handle request time outs?

Want to use code from this post? Check out the license.

Reader Comments

52 Comments

Ben,
Here are some additional thoughts. In your example you set the request timeout to 5 seconds. I understand that was for purposes of the example but lets also examine a fairly normal operation. I can see a page timeout because of the fact that it has to output so much data to a screen but what scenario is a query going to timeout like this? The default setting for a request timeout is 60 seconds. If you have queries that are taking in excess of 60 seconds on a daily basis then I think the sql needs to be examined. I know this article is a "Why & how to fix it" but I just do not see this coming up in the real world. Has this happend to you in a real world application? Just some more thoughts on the subject, great stuff though!

15,848 Comments

Dan,

You are correct. This is not the most relevant real world solution. I guess the places that his happens, I can actually decrease the timeout of something like a CFExecute tag or a CFHttp tag and then if it throws an error, or if I CFTry/CFCatch the error, I can deal with it then.

In fact, on things like Reports where I have loooong running queries, this is actually how I deal with it.

I guess my concern is the "outliers" where something crazy is going on and my system attempts to log the error by it cannot do that as the logging itself takes too much time.

But that said, you are correct... this is not going to be an every day occurence. Something about it just seems strange. But I guess it makes sense. You could theoretically put an infinite loop into your OnError() method. So you need some sort of check to handle that. My gut says that it should have it's own request timeout or something.

48 Comments

I asked a similar question to a great CF mind once and the response: "Don't do anything that would throw an error in your onError" -- meaning basically keep it simple. At most I'd shoot off an email in the onError method. Also a try with an empty catch should at the very least not show any exception info to your users, no?

15,848 Comments

Todd,

I agree with you. I have actually found that any errors that occur in OnError() just error out and are not caught. However, the real problem here is that the error is not of a poor-programming nature; it's due to a lack of time.

I wonder if CFMail would have time to fire off. I will give that a test.

1 Comments

A couple of comments.

1) According to the documentation and a bit of my testing, if an exception is thrown in the onError function, it is thrown to higher exception handlers, first <cferror...> tags then the site-wide error handler.

2) You can put plain HTML in the onError function an it will work in this situation. So one can output a simple message. I have not tried much else yet.

1 Comments

Hi All,

I was having the same problem that you're describing and found that I could process the timeout through onError if the first thing I did in onError was to increase the timeout period.

In my case I increased the timeout in onError to 40 seconds which is 10 seconds more than is specified in the administrator. This gives me 10 seconds to handle any code (e.g. cfmail).

I know it's not very elegant but what the hell :-)

<cffunction naame="onError">

<cfsetting requesttimeout="40">

<cfmail ...>

<cfdump var="#cferror#">

</cfmail>

</cffunction>

3 Comments

Hi Ben,

I know this thread hasn't been touched in almost a year, but I'm out of ideas. I can't get the TIMEOUT parameter of CFQUERY to work for the life of me. I'm using CFMX 7.0.2 with MS SQL Server 2005. This is what I run:

<cfquery name="test" datasource="dsn" timeout="1">
select top 20000 *
from table </cfquery>

<cfoutput>#cfquery.ExecutionTime#</cfoutput>

That query outputs a number that's in the 3000s -- which should never happen, right? Since the timeout is set for 1 second (or 1000ms). Why is this happening? I thought the TIMEOUT paramter works with SQL...

15,848 Comments

@Sung,

I didn't even know the CFQuery tag had a timeout attribute :) If this is not working, it's probably a driver issue. Maybe this only works for certain types of datasources.

3 Comments

Hi Ben,

It's news to me, too -- I didn't realize CFQUERY had a timeout param, either, until today. But I've scoured the net every which way, and it seems like there are a bunch of folks who say this works for JDBC drivers that hook into MS SQL. Which is exactly my setup, so I just don't get it.

I can't even use CFSETTING here. Because if the datasource is unresponsive, even if you have CFSETTING's REQUESTTIMEOUT set to 30 seconds, the page will not time out at the 30-second mark because this is an external action (like CFHTTP). It'll just keep waiting, and when the datasource finally fails, then the CFSETTING will kick in immediately. It's actually quite useless.

15,848 Comments

@Sung,

From what I understand from my own experience, CFSetting only comes into play when control is back in the ColdFusion workflow. So, if a query is taking too long to run, the page won't timeout until the query returns and then ColdFusion tries to take a next action.

3 Comments

@Ben Nadel, yup, I understand it the same way. That's why the TIMEOUT parameter in CFQUERY is really the only way to handle this -- except it just plain isn't working. It's frustrating...

2 Comments

Hi Ben -any chance you have figured this out ? I am simply trying to loop over 5k records and append the key field to a list. it tiems out every time :(
Just hoping you figured out something.
thanks and God Bless
Chris

15,848 Comments

@Chris,

For pages that I know are going to run a long time, I use a larger timeout (via the CFSetting tag). If the onError() does get fired, I typically include *another* CFSetting tag that increases the page timeout in order to allow the error-processing to take place.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel