Controlling SqlConnection timeouts

When performing queries against a SQL Server database, there are a couple of methods readily available. However, an option is missing.

The primary timeout value is that of SqlConnection.ConnectionTimeout. This specifies how long time the SQL Server service has to respond to a connection attempt. You cannot set this value directly, you'll have to set it as part of the connection string:

Data Source=server;Initial Catalog=databaseUser Id=username;Password=password;Connect Timeout=30

Note that the value is expressed in seconds, not milliseconds. The default value is 30 seconds. Secondly, we can use the SqlCommand.CommandTimeout value. This sets the timeout value of a specific query running on SQL Server. The problem with these two is that we're missing a point in the pipeline, which goes:

TCP Connection to SQL Server -> SqlConnection.Open -> SqlCommand.Execute

The last two are covered, but if for some reason the SQL Server is dead, taken off the network, totally overloaded, we may get a timeout on the TCP level - and this could take a while. We currently have no way of controlling this timeout besides a server wide network level setting. Often, it's not desirable to have your application potentially spending several minutes before receiving a TCP timeout - or sometimes simply wait indefinitely. We need some way to control this.

What I present below is an example of a SqlConnection extension method called QuickOpen (in lack of a better name, it isn't quicker, it simply fails quicker). It'll take a timeout parameter in milliseconds, after which it'll throw a simple Exception. You can modify this to a more proper exception, this is just to show the point. Overall, using this method will introduce a slight delay (a couple of ms), so use it only when necessary, or when a couple of ms per SqlConnection.Open doesn't matter.

public static class SqlExtensions
{
	public static void QuickOpen(this SqlConnection conn, int timeout)
	{
		// We'll use a Stopwatch here for simplicity. A comparison to a stored DateTime.Now value could also be used
		Stopwatch sw = new Stopwatch();
		bool connectSuccess = false;

		// Try to open the connection, if anything goes wrong, make sure we set connectSuccess = false
		Thread t = new Thread(delegate()
		{
			try
			{
				sw.Start();
				conn.Open();
				connectSuccess = true;
			}
			catch { }
		});

		// Make sure it's marked as a background thread so it'll get cleaned up automatically
		t.IsBackground = true;
		t.Start();

		// Keep trying to join the thread until we either succeed or the timeout value has been exceeded
		while (timeout > sw.ElapsedMilliseconds)
			if (t.Join(1))
				break;

		// If we didn't connect successfully, throw an exception
		if (!connectSuccess)
			throw new Exception("Timed out while trying to connect.");
	}
}

kick it on DotNetKicks.com


Comments

Michael Vermilion | May 9th, 2008, 6:35 PM

This helped me out a lot. In my situation on Windows Mobile I did it a little differently. There was no StopWatch in the compact framework so I tried the DateTime idea you suggested, but it didn't work reliably. It would eventually start returning false after using it several times. The following seems to work reliably:

t.IsBackground = true;
t.Start();
t.Join(timeout);

Mark S. Rasmussen | May 9th, 2008, 10:21 PM

Michael,

That's a great way to simplify my functionality. I love it when I'm reminded of even more KISS'ish ways to accomplish the same functionality :)

Michael Vermilion | May 10th, 2008, 7:50 AM

I could ramble on for hours about everything I've done today, but my application finally works correctly thanks to you. BTW I think I might have also added t.Abort() after the Join() to resolve some problem I was having, although there were so many problems mixing together that it's hard for me to say whether that was needed. Also, I just upgraded my project to Compact Framework 3.5 and MS has now implemented the StopWatch. For another, MS has now added a sound player into the Compact Framework. Anyway, I spent the whole day trying to solve problems with my application losing wifi connection. I had sounds playing that were making calls to an external method and I think funny things were happening when I stressed that along with the connection timeout. Anyway making everything syncronous, including the SQL connection blocking the main thread and the SoundPlayer blocking the main thread (ie connect/disconnect sounds) seems to have done it.

U-Da-Man

Freddie | Jan 5th, 2009, 7:34 AM

Thank you so much.
It helped me a lot.

hosting | Oct 27th, 2009, 11:18 AM

Need help choosing name for web design marketing business?

hosting | Oct 27th, 2009, 11:22 AM

Need help choosing name for web design marketing business?

Daniel | Jun 21st, 2010, 1:23 PM

Very easy to use thanks. i realy appreciated it. i like its simplicity. will be useing it soon. micheal vermillion said he had an issue with it but with i a little tinkering it worked so every ones happy.

Michael Vermilion | Jun 21st, 2010, 7:13 PM

Daniel - Glad you got it working. I've been using this in production for a year now and it works great. I haven't touched this system in that time and haven't got any complaints about this not working, so props to Mark. Finally got some enhancement requests recently for merge replication, which looks interesting.

Create a Website | Jul 17th, 2010, 9:07 AM

How do I create and access a SQL database from two computers on a network?

seo company | Aug 27th, 2010, 12:51 PM

How to make SQL Server connection in VB2005?

Add comment

After you have posted a comment, an email will be sent to the provided email address. Before your comment is activated, you will have to click the confirmation link within the email.

Name:

Email (only used for validation):

Website (optional):

Message:

Notify me when new comments are added:

Please type the following letters into the box below:  

Post!