Reputation: 5138
We have some code that uses a System.Timers.Timer to ping a database connection and also check on the existence of some mounted files. The code to set up the timer is:
m_Timer = new System.Timers.Timer(TimeSpan.FromSeconds(10).TotalMilliseconds);
m_Timer.Elapsed += (object xiSender, ElapsedEventArgs xiEventArgs) =>
{
PingRemoteFolder();
PingDatabase();
};
This happens in the constructor of a singleton class.
I know that System.Timers.Timer will use multiple threads from the thread pool if the operation it is trying to run each time takes longer than the interval provided, but that is not the case in our situation.
The timer's event seems to be ocurring much more often than every 10 seconds, and is using up to 4 or 5 threads at a time.
Any ideas? Also we think this may be related to another situation we have where we are getting stack corruption on the main thread of a WPF application that uses a worker thread to check on properties of the class that uses this timer to set their values.
.NET version 4.0 on Windows 2008R2
Edit:
Also when we get the stack corruption on the main thread of the WPF application, an InvalidOperationException is thrown in one of the methods the timer event handler calls with the message "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."
PingRemoteFolder() just tries to do Directory.GetFiles("somepath")
PingDatabase():
private void PingDatabase()
{
if(!string.IsNullOrEmpty(CurrentInstance.Name) && DoPing)
{
SqlConnection sqlConnection = null;
try
{
SqlConnectionStringBuilder sqlConnectionStringBuilder = new SqlConnectionStringBuilder();
sqlConnectionStringBuilder.DataSource = CurrentInstance.Instance;
sqlConnectionStringBuilder.IntegratedSecurity = CurrentInstance.AuthenticationMode == SmoAuthenticationMode.WindowsAuthentication;
sqlConnectionStringBuilder.InitialCatalog = CurrentInstance.Name;
if(CurrentInstance.AuthenticationMode == SmoAuthenticationMode.SqlServerAuthentication)
{
sqlConnectionStringBuilder.UserID = CurrentInstance.UserName;
sqlConnectionStringBuilder.Password = CurrentInstance.Password;
}
sqlConnection = new SqlConnection(sqlConnectionStringBuilder.ToString());
sqlConnection.Open();
Assert.Condition(sqlConnection.State == ConnectionState.Open, "sqlConnection.State == ConnectionState.Open");
IsCurrentInstanceReachable = true;
}
catch(Exception ex)
{
IsCurrentInstanceReachable = false;
CurrentInstance.Name = string.Empty;
}
finally
{
if(sqlConnection != null && (sqlConnection.State != ConnectionState.Closed && sqlConnection.State != ConnectionState.Broken))
{
SqlConnection.ClearPool(sqlConnection);
sqlConnection.Close();
sqlConnection = null;
}
}
}
}
Upvotes: 1
Views: 1357
Reputation: 559
It sounds like there is a connection pool issue with the database, and the timer callback blocks on the call to PingDatabase(). This causes multiple timer callback threads to exist at the same time. You can do a quick check of this by putting a call to m_Timer.Enabled = false at the top of the timer function and a call to m_Timer.Enabled = true at the end of the function. This should result in only one thread existing at any given time.
m_Timer.Elapsed += (object xiSender, ElapsedEventArgs xiEventArgs) =>
{
m_Timer.Enabled = false;
PingRemoteFolder();
PingDatabase();
m_Timer.Enabled = true;
};
Upvotes: 2