“Nothing on the web should ever take more than five seconds,” a mentor of mine once said. I’ve kept that in mind every time I’ve ever had to deal with a timeout issue.
“This report could take over thirty minutes to run,” my clients always seem to say. And since my clients pay my mentors to philosophize at me, they win.
Even when they ask for things that are expensive, risky, or, even on a certain level wrong, the best I can do is present the proper way to do things. But their boss’ boss’ boss needs it last week, so on occasions like this, it usually comes down to making as few hacks as I can. And that’s not to say that, for example, a session timeout time of 99999 is necessarily a bad thing; you just need to know what you’re doing before making such a decision.
And indeed, in this week’s episode of my professional life, my client asked me to bump the timeout times on our entire web app to thirty minutes to accommodate one report. In my mind, it was only one little web.config setting that needed to be updated; it should only take a second. But as it turns out, with complicated web applications, there are so many inheriting, overriding, counter-intuitive settings to deal with that this becomes an arduous task to complete successfully…and more importantly, correctly.
So since I couldn’t find one on Google, I’m going to provide a hierarchical list of servers, files, and utilities that ultimately govern the timeout settings of your ASP.NET 2.0 web application. Here is the “stack” of mechanisms that dictate timeout times, and in the parenthetical the objects exposed to developers to manipulate them:
This is the highest level of configuration for.NET. The machine.config file governs default settings on the entire machine. Anything inherited from this file is used by your app if not explicitly set lower in the stack. You can find a lot of Microsoft’s prescribed default values for various aspects of development here.
Don’t modify it unless you really really really have to; you could break EVERYTHING. The point of such a high level config file is to provide default values so you don’t have to, not to allow server-wide hacks.
As far as timeouts go, the main setting defined here is the executionTimeout attribute of the node under . From Microsoft: “The ExecutionTimeout indicates the maximum number of seconds a request is allowed to execute before being automatically shut down by ASP.NET. The default is 90 seconds. (MSDN)”
In other words, the worker thread that IIS assigns to handle the postback, run the server-side code, and send the response back to the client has a minute and a half to do its job. So if there’s NOTHING else to govern timeout times between a postback event on a page and the machine.config file on the server, your code has 90 seconds to run.
IIS is the administrative tool used to configure ASP.NET applications that run under it. ASP.NET is the technology used to create web applications; IIS is the application on the server that actually spins up a process (w3wp.exe) to run the code. I’m sure you all know this, but it’s a very important distinction, since some IIS timeout settings are independent of the technology used.
These settings are actually a little lower in the stack. The only thing you can do at this level is edit them with the IIS metabase, which is basically its own personal registry implemented as an XML file. You’ll want to mess with this even less than the machine.config. If something is pointing you to edit the IIS metabase, then you are probably way off track.
The app pool is basically an app domain spun up by IIS. It allows you access to the process that is running your ASP.NET code, and provides the levels of isolation that .NET gives us between our applications. The following settings are available in the first two tabs of the properties window for an app pool in IIS.
But think about it! At twenty minutes of idle time, the session object will not be garbage collected, since it doesn’t timeout for another forty minutes. However, IIS has now shut down the worker process pursuant to the twenty minute timeout! Objects are dead when their process is killed. Therefore, a request made after this time will cause IIS to spin up a new session (and process if necessary), and your app will essentially restart. So in this case, you won’t actually get a timeout; your app’s current page will just quietly reload itself.
The web site is a logical and poorly-named collection of virtual directories. Each virtual directory is actually a web app; the web site concept contains settings that its children can inherit and override. The one setting here that affects timeouts is the HTTP Keep-Alives, which can be enabled and configured to a certain number of seconds.
What this does is keeps a single connection open between the browser to the server, so that the client doesn’t have to inefficiently make a new connection for every request to download each image, file, etc. In fact, this is required for other types of requests, such as Windows auth; disabling it will cause the request to fail.
So what happens if this times out? Well, let’s think it through. If our execution timeout is set to five minutes and HTTP Keep-Alives are at two minutes, we’ll have a problem. At two minutes after, for example, a button click, ASP.NET will keep the actual thread running in memory, and IIS will close the connection. Remember, at this point in the page lifecycle, this thread is just a normal .NET thread executing in memory. If it takes longer than five minutes, ASP.NET will kill it. If not, it’ll go to return a response, see that the connection is closed, and then probably just go to a bar instead.
This situation actually (as a side note) acts as an asynchronous request with no callback. If you click a button that’ll do something you know takes a long time and the user won’t want to wait, kick it off, then just display a message that the operation is working and to try back later. If that request creates a file on the server, for example, and the connection closes, it’ll keep going, and if it doesn’t blow up, actually finish successfully! Talk about embracing the timeout!
By the time we get down to this level, we are finally dealing with a single web application and its trusty web.config file. Just about everything you can do in the machine.config you can override in the web.config, and unlike some of the aforementioned situations above, it’ll inherit normally. Also, this is the point where we associate our app with an app pool, so it’ll absorb those settings as well.
However, there are some contradictory things going on. If you right click the virtual directory in IIS, select “Properties” and click “Configuration” on the “Directory” tab, you’ll get a popup that has all kinds of settings that appear to handle some of the same things as our web.config, most notably, session timeout!
Well, if your session is timing out, resist the urge to even come to this window; these settings are for Classic ASP apps only! For ASP.NET, make these changes in your web.config file. If the appliction continues to timeout, then something else is amiss. Remember, you can actually have a web.config in each sub folder of your app, and these inherit settings form their parent web.configs and affect sibling pages.
The session object is a child of an application object, and is created whenever a new instance of a browser makes an initial request. It is destroyed, essentially, when it times out and is garbage collected. As stated in the previous section, this timeout is controlled via the web.config file.
Session timeout is probably the most common one I’ve seen. Since we’re on the web, almost all of our control and data persistence is stored in this object, so if it goes, the app is pretty much useless. Keep in mind that it doesn’t make sense for request timeouts that are longer than session timeouts, unless you are working asynchronously.
We all know what a page is. In the page directive at the top of an ASPX page’s markup, we can override some web.config settings and make them specific to the current page. This is helpful in a pinch if you have a rogue page in your app that doesn’t follow the rules, and it’s too much work to bend them.
Here we can disable session state altogether, if we wish. However, I’ve never really found this method to be very useful; this level of granularity between settings inheritance is more than I’ve needed.
Now here is where things get interesting. When your page posts back to the server, it is getting a thread from IIS that has a certain amount of time to do its thing. Now what if that request needs to make a request of its own? And what if this new request actually times out? Situations like these have given me the most problems…and have caused my patience to occasionally timeout as well.
The bullets under these are examples of requests that your page may make during its round trip to the server for processing. The first one is a web request. These could be a simple call to a web reference or actually constructing an HttpWebResponse object and calling it yourself. Remember, these objects have timeouts of their own!
So if, for example, your execution timeout is upped to five minutes, but the timeout on a web service call is never set, it’ll default to 90 seconds. If that times out, you’ll get an exception that…guess what…the request timed out! “Which request?” you’ll no doubt instinctively ask yourself. Well, it’s the call to the web service. Now if the two timeouts were switched, then the page’s request will timeout, leaving the web service call to continue on its merry way.
Same deal with database calls using ADO.NET. If you don’t set the timeout on the command object, your query has thirty seconds to shine. The reason that this isn’t as big a problem as other timeouts is that not only do you actually get a very descriptive exception when it does occur, and it’s easy to fix.
The final request timeout comes with all the new ASP.NET AJAX stuff. Script manger controls have a property called “AsyncPostBackTimeout.” This timeout will actually override the execution timeout whenever a postback occurs inside an update panel. So if you’ve upped your execution timeout and still find that sometimes requests are being killed right around thirty seconds, check your script manager; these timeouts can be tricky to find!
I don’t know about you, but five pages of timeout talk is about all I can stomach. I hope this sheds some light on the topic, and causes fewer web apps out there to have requests that are allowed to execute for days when the session times out after twenty minutes!