I get this exception in my error log..
The timeout period elapsed prior to
obtaining a connection from the pool.
Restarting the IIS makes me to login back to my app.. so where do you think the issue is? Is it in IIS property setting?
Code is something like this:
MySqlConnection connection = null;
try
{
connection = MySqlConnectionHandler.OpenConnection();
string strText =string.Empty;
strText = "<<sql statement>>";
using (MySqlCommand cmd = new MySqlCommand(strText, connection))
{
cmd.Parameters.Add(new MySqlParameter("ID", MySqlDbType.Int32));
cmd.Parameters["ID"].Value = 100;
cmd.ExecuteNonQuery();
}
}
finally
{
MySqlConnectionHandler.CloseConnection(connection);
}
My CloseConnection method internally has
if (con != null)
{
con.Close();
con.Dispose();
}
That almost always means you aren't calling Dispose() on your connections, and you have saturated the pool until GC runs - which it probably won't if your app is now dead. Essentially, you have opened connections successively over a period of time (without ever giving them back), and now there are none left. Solution: give them back to the pool when you are done.
Whenever you use something like a connection, use a using statement, or some other mechanism to ensure it is disposed promptly when you are done with it. The same applies to anything IDisposable, but connections are particularly vulnerable to this.
Since you say you do call Dispose()...
I would try two things. Temporarily increase your connection timeout to see if that's the issue:
MySqlCommand.CommandTimeout = 45; //in seconds
This will slow your application so you should only use it for troubleshooting. If it is you need to optimize your SQL query.
Alternately, your connection pool may be exceeded, so you may need to bump that up.
Related
I have a webservice running on IIS, which contains the class to connect to the SQL server. Most of the time, we are able to connect the SQL server using the below code. But some time we could not connect the sql server. We are not getting any error. Here is the source code:
public SqlConnection DbConnectSql()
{
string str = "Server=xxxx\xxx;database=production;Timeout=60000;user id=sa;password=888*;";
_con = new SqlConnection(str);
if (_con.State == ConnectionState.Open)
_con.Close();
_con.Open();
return _con;
}
We are not getting any response during the execution of _con.Open();. We could not understand why we are not getting any response. I have to restart the IIS every 2 days to open the SQL connection. Can anyone let me know the why I have to restart the IIS to work _con.Open(); method?
Here's an interleaving of two calls to DbConnectSql that will a) end up with two threads sharing use of one connection object and b) leaks an open connection object:
//Thread 1
public SqlConnection DbConnectSql()
{
string str = ...;
_con = new SqlConnection(str);
if (_con.State == ConnectionState.Open)
_con.Close();
_con.Open();
//Thread 2
public SqlConnection DbConnectSql()
{
string str = ...;
//-->Look, thread 2 is overwriting _con-->
_con = new SqlConnection(str);
return _con;
}
if (_con.State == ConnectionState.Open)
_con.Close();
_con.Open();
return _con;
}
If we're lucky, then the first caller won't try to use the connection object before the second caller gets around to calling Open on it1. But the connection created by the first caller has been opened and now nobody has a reference to it.
You'll be getting errors because the connection pool (eventually) becomes exhausted and so the Open call will throw an exception. Why you don't see the exception isn't diagnosable from the code shown.
You're probably being lucky to last 2 days at a time, because these connections are eligible for garbage collection and so will eventually be returned to the connection pool.
Far better to just share the connection string around. Construct SqlConnection (and SqlCommand) objects in using statements that keep them nicely locally scoped and ensures that they are cleaned up neatly. You don't need this DbConnectSql function. It's doing more harm than good.
1And there are likely to be other possible errors here, if one caller tries to retrieve a result set whilst the other caller is still retrieving one.
Some first things that people learned in their early use of MySQL that closing connection right after its usage is important, but why is this so important? Well, if we do it on a website it can save some server resource (as described here) But why we should do that on a .NET desktop application? Does it share the same issues with web application? Or are there others?
If you use connection pooling you won't close the physical connection by calling con.Close, you just tell the pool that this connection can be used. If you call database stuff in a loop you'll get exceptions like "too many open connections" quickly if you don't close them.
Check this:
for (int i = 0; i < 1000; i++)
{
var con = new SqlConnection(Properties.Settings.Default.ConnectionString);
con.Open();
var cmd = new SqlCommand("Select 1", con);
var rd = cmd.ExecuteReader();
while (rd.Read())
Console.WriteLine("{0}) {1}", i, rd.GetInt32(0));
}
One of the possible exceptions:
Timeout expired. The timeout period elapsed prior to obtaining a
connection from the pool. This may have occurred because all pooled
connections were in use and max pool size was reached.
By the way, the same is true for a MySqlConnection.
This is the correct way, use the using statement on all types implementing IDsiposable:
using (var con = new SqlConnection(Properties.Settings.Default.ConnectionString))
{
con.Open();
for (int i = 0; i < 1000; i++)
{
using(var cmd = new SqlCommand("Select 1", con))
using (var rd = cmd.ExecuteReader())
while (rd.Read())
Console.WriteLine("{0}) {1}", i, rd.GetInt32(0));
}
}// no need to close it with the using statement, will be done in connection.Dispose
Yes I think it is important to close out your connection rather than leaving it open or allowing the garbage collector to eventually handle it. There are a couple of reason why you should do this and below that I'll describe the best method for how
WHY:
So you've opened a connection to the database and sent some data back and forth along this pipeline and now have the results you were looking for. Ideally at this point you do something else with the data and the end results of your application is achieved.
Once you have the data from the database you don't need it anymore, its part in this is done so leaving the connection open does nothing but hold up memory and increase the number of connections the database and your application has to keep track of and possibly pushing you closer to your maximum number of connections limit.
"But wait! I have to make a lot of database calls in rapid
succession!"
Okay no problem, open the connection run your calls and then close it out again. Opening a connection to a database in a "modern" application isn't going to cost you a significant amount of computing power/time, while explicitly closing out a connection does nothing but help (frees up memory, lowers your number of current connections).
So that is the why, here is the how
HOW:
So depending on how you are connecting to your MySQL database you a probably using an IDisposible object to help manage the connection. Here is what MSDN has to say on using an IDisposable:
As a rule, when you use an IDisposable object, you should declare and
instantiate it in a using statement. The using statement calls the
Dispose method on the object in the correct way, and (when you use it
as shown earlier) it also causes the object itself to go out of scope
as soon as Dispose is called. Within the using block, the object is
read-only and cannot be modified or reassigned.
Here is my personal take on the subject:
Using a using block helps to keep your code cleaner (readability)
Using a usingblock helps to keep your code clear (memory wise), it will "automagically" clean up unused items
With a usingblock it helps to prevent using a previous connection from being used accidentally as it will automatically close out the connection when you are done with it.
In short, I think it is important to close connections properly, preferably with a con.close() type statement method in combination with a using block
As pointed out in the comments this is also a very good question/answer similar to yours: Why always close Database connection?
According to Microsoft's article (SQL Server Connection Pooling (ADO.NET)),
When connection pooling is enabled, and if a timeout error or other login error occurs, an exception will be thrown and subsequent connection attempts will fail for the next five seconds, the "blocking period". If the application attempts to connect within the blocking period, the first exception will be thrown again. After the blocking period ends, another connection failure by the application will result in a blocking period that is twice as long as the previous blocking period. Subsequent failures after a blocking period ends will result in a new blocking periods that is twice as long as the previous blocking period, up to a maximum of five minutes.
How would you detect that the blocking period is active? I would assume that there is some property to check before attempting the connection so that you could avoid extending the blocking period.
There shouldn't be a need to check if you're in a blocking period to avoid extending it. As it says in the excerpt above, any attempts to connect during the blocking period will re-throw the first exception, it says nothing about extending the blocking period. However, each new blocking period will be twice as long as the previous.
In my experience, the exceptions that get thrown (due to timeouts, connection leaks, etc.) are either environmental issues or failing to properly close/dispose connections. It's a good idea to log these exceptions so that you can track down the real issue.
If you do keep coming across a timeout exception, you could catch it and try to clear all the pools, but it's likely due to a connection leak. You'll want to make sure you're wrapping your connections with a using statement, which will help to close/dispose of your connections when you're done with them or if an exception occurs.
using(SqlConnection connection = new SqlConnection("connection_string"))
{
using(SqlCommand command = new SqlCommand())
{
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandTimeout = [some timeout value];
command.CommandText = "Update SomeTable Set Value = 1";
connection.Open();
command.ExecuteNonQuery();
}
}
In addition to the ClientConnectionId field,
The SqlException.Message will also be reference-equal. That is, the cached string will be returned for connections that fail within the "blocking period".
However, this is also an implementation detail and may change.
Unfortunately there is no easy way to detect if you are in the ADO.NET "Blocking Period" or not (without resorting to something fragile like reflection).
However, if you are using .Net 4.5 or later, then you can detect if the last exception you observed from Open/OpenAsync is duplicated or not by looking at the ClientConnectionId of the SqlException and comparing that to the id of the last SqlException that you've seen (since the exceptions are duplicated, the ids are duplicated as well).
Assuming that you have a single place where you create\open SqlConnections for a single connection string, you can do the following:
public static class DataAccessLayer
{
// Single connection string that all connections use
private static readonly string _connectionString = "server=(local);integrated security=true;";
// Stores that last observed connection if when opening a connection
// NOTE: Using an object so that the Volatile methods will work
private static object _lastErrorConnectionId = Guid.Empty;
public static SqlConnection GetOpenedConnection()
{
try
{
SqlConnection connection = new SqlConnection(_connectionString);
connection.Open();
return connection;
}
catch (SqlException ex)
{
// Did the connection open get to the point of creating an internal connection?
if (ex.ClientConnectionId != Guid.Empty)
{
// Verify that the connection id is something new
var lastId = (Guid)Volatile.Read(ref _lastErrorConnectionId);
if (ex.ClientConnectionId != lastId)
{
// New error, save id and fall-through to re-throw
// NOTE: There is a small timing window here where multiple threads could end up switching this between
// a duplicated id and a new id. Since this is unlikely and will only cause a few additional exceptions to be
// thrown\logged, there isn't a large need for a lock here.
Volatile.Write(ref _lastErrorConnectionId, (object)ex.ClientConnectionId);
}
else
{
// Duplicate error
throw new DuplicatedConnectionOpenException(_connectionString, ex);
}
}
// If we are here, then this is a new exception
throw;
}
}
}
public class DuplicatedConnectionOpenException : Exception
{
public string ConnectionString { get; private set; }
internal DuplicatedConnectionOpenException(string connectionString, SqlException innerException)
: base("Hit the connection pool block-out period and a duplicated SqlException was thrown", innerException)
{
ConnectionString = connectionString;
}
}
Now if you call GetOpenedConnection and you see a DuplicatedConnectionOpenException being thrown, you will know that you have hit the "Blocking Period".
NOTE: I'm using Volatile Read/Write here instead of a lock since I'm opting for better performance versus being 100% accurate about being in the "Blocking Period". If you would prefer the accuracy you can use a lock instead.
Additionally, I do have code that works as an extension method on SqlConnection and can handle multiple connection strings, but its performance is much worse since it uses a ConcurrentDictionary to map connection strings to connection ids.
In my Windows application I try to connect to SQL Server 2008 with following code:
SqlConnection connection = new SqlConnection(Properties.Settings.Default.KargarBandarConnectionString);
SqlCommand command = new SqlCommand("Select IsAdmin from Users where UserName=#UserName And Password=#Password", connection);
SqlDataReader dataReader = null;
command.Parameters.AddWithValue("#UserName", UserNameTextBox.Text.Trim());
command.Parameters.AddWithValue("#Password", PasswordTextBox.Text);
try
{
connection.Open();
dataReader = command.ExecuteReader();
if (dataReader.HasRows)
{
while (dataReader.Read())
{
IsAdmin = dataReader.GetBoolean(0);
}
this.DialogResult = DialogResult.OK;
}
else
{
FMessageBox.ShowWarning("error");
UserNameTextBox.Focus();
}
}
catch (Exception ex)
{
if (progressForm != null)
progressForm.Close();
FMessageBox.ShowError(ex.Message);
}
finally
{
if (dataReader != null)
{
dataReader.Close();
dataReader.Dispose();
}
if (connection != null)
{
connection.Close();
connection.Dispose();
}
}
Everything works properly, but sometimes I get the following error:
timeout expired. the timeout period elapsed prior to obtaining a
connection from the pool ...
How can this be solved?
The reason you're getting this exception is because you have exhausted your connection pool and the number of "available" connections in your application.
Every time you open a connection, one is pulled from the connection pool if possible, or a new one is created if not.
However, to prevent galloping usage of connections, a limit of 100 (I think this is configurable) exists, and if you try to use more than 100 simultaneous connections, the code will not create new ones, and instead sit down to wait for one to be returned to the pool, and in this case you get a timeout if it sits too long.
So, for the particular example of code you've shown, I would:
Close the connection before I show an error messages to the user
However, unless 100 users are seeing the error message and leaving it there at the same time, it is unlikely the code you've shown is the cause of this problem.
Other than that, I would go through the entire application and ensure you don't have any connection leaks other places.
This particular type of exception can occur in one spot even though the problem is somewhere else. Example: A report is leaking an open connection every time it runs, and you run it 100 times successfully, then someone tries to log in, and the exception occurs in the login form.
That happens if you either:
leak connections (leaving them for GC to deal with rather than disposing them)
just have too much happening, such that the pool is exhausted
The first is the most common, and I expect it relates a lot to the fact that you are over-complication your error handling. This makes it easy to miss, and hard to spot that you've missed it. The code shown looks OK, but it would be far preferable to use using blocks for all the IDisposable elements, rather than finally. Also; don't keep the connection while you show modal things like the message box, unless you need the connection afterwards. Frankly, a lot of benefit here could be made by cleanly separating the UI and data-access code, then there is not temptation to stick a message-box in the middle of a database query.
However! To be explicit, I believe this code is the victim of some other code that is hogging connections. Look at your other data access code for the cause of this.
Refactor your code to look something like this. Implement using blocks. The other answers here are very important, be sure to understand them.
bool res=false;
try
{
using(var connection = new SqlConnection(Properties.Settings.Default.KargarBandarConnectionString))
using(var cmd = conn.CreateCommand())
{
cmd.commandText = "Select IsAdmin from Users where UserName=#UserName And HashedAndSaltedPassword=#PwdHash";
cmd.Parameters.AddWithValue("#UserName", UserNameTextBox.Text.Trim());
cmd.Parameters.AddWithValue("#PwdHash", SaltAndHash(PasswordTextBox.Text));
connection.Open();
var result = cmd.ExecuteScalar();
if (result!=null)
{
res=bool.Parse(result);
this.DialogResult = DialogResult.OK;
}
}
}
catch (Exception ex)
{
if (progressForm != null){progressForm.Close();}
FMessageBox.ShowError(ex.Message);
}
if(res==false)
{
FMessageBox.ShowWarning("error");
UserNameTextBox.Focus();
}
I´m using Transaction Binding=Explicit Unbind in the connection string as recommended here since I´m also using TransactionScope with timeout. The problem is that the connections does not seem to close after being disposed and eventually there are no more connections available in the connection pool. I got the same result when I modified the TransactionTimeoutIssueDemo (see the link) and ran TransactionScopeTest() (with the explicit unbind connection string) enough times in a loop to use up all available connections in the connection pool. Default value for connections in the pool is 100 but this can be changed by using the setting Max Pool Size =10 for instance. It seems that the connections will not be released when using explicit unbind even though both the SqlConnection and the TransactionScope are used with the using clause. Anyone know how to handle this?
The connections only seem to stay in the pool and not being reused in case you get an exception, just like the example. If you increase the timeout the connection will be reused.
A workaround to this problem is to clear the connection pool in case you get an exception like this:
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
try
{
Console.WriteLine("Server is {0}", con.ServerVersion);
Console.WriteLine("Clr is {0}", Environment.Version);
for (int i = 0; i < 5; i++)
{
using (SqlCommand cmd = con.CreateCommand())
{
cmd.CommandText = "insert into TXTEST values ( " + i + " )";
cmd.ExecuteNonQuery();
}
Console.WriteLine("Row inserted");
}
Thread.Sleep(TimeSpan.FromSeconds(1));
}
catch
{
SqlConnection.ClearPool(con);
throw;
}
}
In most cases the transaction will complete within the timeout and everything will be fine and dandy. When the transaction actually do timeout you clear the pool in order to clean up the dirty connections that won't get reused. This will of course affect other connections in the pool that isn't affected by this problem.
This is a ugly workaround but it seems to work.
For what it's worth, this issue was fixed in .Net 4.0.