I have a Windows services running in .NET 4.5. Everything works fine. However, when my service encounters a SqlException, it hangs (turns into a zombie).
I have a timer (System.Timers) that calls process. In process, locate cmd.ExecuteReader(). If I remove EXECUTE permissions from the stored procedure, I receive a SqlException (as expected). When this happens, the service simply hangs.
I would have expected one of the try {} catch blocks to capture the exception and exit the method gracefully. However, the system appears to hang on this call. I had a number of Trace statements in the code. I removed them so it would be easier to read.
private void TimerForNotification_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
TimerForNotification.Stop();
int count = new GetSMSNotifications().process();
TimerForNotification.Start();
}
public int process()
{
int count = 0;
// Get the ConnectionStrings collection.
ConnectionStringSettings connections = ConfigurationManager.ConnectionStrings["DE_OLTP"];
try
{
using (SqlConnection conn = new SqlConnection(connections.ConnectionString))
{
conn.Open();
SqlCommand cmd = new SqlCommand("[dbo].[get_SMSToSend]", conn);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
try
{
SqlDataReader dr = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
while (dr.Read())
{
// increment counter
count++;
string destinationAddress = Convert.ToString(dr[dr.GetOrdinal("DestinationAddress")]);
string alertMessage = Convert.ToString(dr[dr.GetOrdinal("Content")]);
// Send out the notification
sendPush(destinationAddress, alertMessage);
}
dr.Close();
}
catch (SqlException se)
{
DELog.Log.Error(se);
}
}
}
catch (Exception ex)
{
DELog.Log.Error(ex);
}
return count;
}
Interestingly, I created a console app that calls the above method and the try {} catch block works as expected.
I don't see any unhandled exceptions in the event log.
Thoughts?
Problem solved. The reason why it appeared my service was hanging is because I was a missing a reference to Entity.Framework.dll. When the service ran into an exception, the EF dll could not be found. I use the EF in my logging layer.
I was able to discover this issue by installing my service and then ATTACHing to the run process.
Try these things:
Add trace line to these:
TimerForNotification.Stop();
try
{
int count = new GetSMSNotifications().process();
}
catch (Exception ex)
{
// trace line here with ex.ToString().
}
TimerForNotification.Start();
// trace line here stating, i started at DateTime.Now;
Remove execute permissions and see if the above code generates a trace line.
If it does, then the exception details will show up. (even though your method looks very safe) Fix it accordingly.
If the catch doesn't trace, then you should see trace lines for the post start trace which means the service is working as expected.
Related
The state of the connection stays active in pool, when there is an exception while executing a query or stored procedure through c#.
The Npgsql version that I am using is 4.1.7.
Here is the code that I am trying to execute.
NpgsqlCommand cmd = null;
NpgsqlDataAdapter sda = null;
NpgsqlConnection conn = null;
try {
string sql = "a_test";
conn = new NpgsqlConnection("Server=localhost;Port=5432;Username=admin;Password=test;Database=majordb;SearchPath=dbs;CommandTimeout=300;MaxPoolSize=500;Connection Idle Lifetime=180;Connection Pruning Interval=5;");
cmd = new NpgsqlCommand(sql);
cmd.CommandType = CommandType.StoredProcedure;
sda = new NpgsqlDataAdapter(cmd);
cmd.Connection = conn;
sda.Fill(dataTable);
}
catch (Exception e) {
//log
}
finally {
if(null != sda)
{
try
{
sda.Dispose();
}
catch (Exception)
{
}
}
try
{
cmd.Connection.Close();
cmd.Connection.Dispose();
}
catch (Exception)
{
}
try
{
cmd.Dispose();
}
catch (Exception)
{
}
}
If the above code executes properly without any exception, the connection state in pool goes to idle, which is correct. But if an exception occurs while executing, like below:
"Npgsql.NpgsqlException (0x80004005): Exception while reading from stream --->
System.IO.IOException: Unable to read data from the transport connection: A connection attempt
failed because the connected party did not properly respond after a period of time, or established
connection failed because connected host has failed to respond."
The connection state in pool shows as active for about 5 mins or so, even though the close/dispose methods are called in finally block. This means the close/dispose did not properly executed by Npgsql. If the program keeps the connection state in pool active for every connection ran within 5 mins, then there can be an issue with MaxPoolSize error.
I wanted to see the connection state to idle, even when there is an exception. How do I do this.
Please note: I am not looking for a solution to the exception that I listed above. I am looking for a solution where the connection state is changed to idle from active when there is an exception while executing the above code.
To know if the connection state is active or not I used the following query:
SELECT
pid,
usename,
application_name,
datname,
client_addr,
rank() over (partition by client_addr order by backend_start ASC) as rank,
state,
state_change,
current_timestamp,
query,
query_start,
backend_start,
FROM
pg_stat_activity
WHERE
pid <> pg_backend_pid( )
AND
application_name !~ '(?:psql)|(?:pgAdmin.+)'
AND
datname = current_database()
AND
usename = current_user
Any help is really appreciated.
I am using C# in Visual Studio 2019, with Xamarin.Forms, and SQl in SSMS 2018 and have the below code (where [] is used to replace unneccessary information)
try
{
using(SqlConnection connection = new SqlConnection())
{
connection.ConnectionString = "Server=[ServerName]; Database=[DatabaseName]; User Id= [UserID]; Password=[Password]";
connection.Open();
SqlCommand command = new SqlCommand("SELECT * from [TableName]", connection);
[Does stuff here]
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex)
}
When I run this, it hangs indefinitely at connection.Open(). Debug mode continues to run and appears to move on from Connection.Open(), but never reaches the next line.
I have attempted this with different versions of the ConnectionString, using different databases and with Trusted_Connection=true instead of specifiying the username and password but they have made no difference. Adding Connection Timeout = 5 to the connectionString has no effect.
I believe it is probably an issue with my settings in SQL but as I am a novice with this I have no idea where to start and the similar forums posts I have checked have been given answers along the lines of Connection Timeout (Connection.open for hangs indefinitely, no exception is thrown) or never got answered.
Any advice would be greatly appreciated.
Can you log into SSMS with the credentials that are in the connection string?
Otherwise I've had luck making sure the connection isn't already open or broken first:
if (connection.State == ConnectionState.Closed || connection.State == ConnectionState.Broken)
{
connection.Open();
}
Can you try code changing line as per below -
connection.ConnectionString = "Data Source=[ServerName]; Initial Catalog=[DatabaseName]; Integrated Security=SSPI;"
A workaround to this problem is to pass in a cancellation token instance as shown below,
public async Task<IEnumerable<Toy>> ShowToybox(CancellationToken t)
{
// notice I turned this into an async operation.
// Reason is to let this operation to find its way out if something happens
var connString = "Server=xyz; Connection Timeout=250";
//Timeout might not happen, if that is not the case see below..
using(SqlConnection connection = new SqlConnection(connString))
{
if ( t.IsCancellationRequested) {
t.ThrowIfCancellationRequested();
}
// await query here. To fetch records from the toybox table
return matches;
}
Main issue is that you cannot trust connection.State
To get this working, code that consumes this method should expect something might go wrong.
class Program
{
static void Main()
{
var box = new ToxBox(); //it has method shown above
var s = new CancellationTokenSource();
s.CancelAfter(400); //it prevents method from hanging
var task = Task.Run(() = box.ShowToybox(s.Token));
try
{
task.Wait(s.Token);
var myToys = task.Result();
Console.WriteLine($"I have {myToys.Count()} toys");
}
catch (Exception e)
{
Console.WriteLine("Something happened!");
}
finally
{
s.Dispose(); //this is important
}
}
}
See https://learn.microsoft.com/en-us/dotnet/standard/threading/cancellation-in-managed-threads
I have a C# project that is working with TCP socket in an asynchronous way.
Every request comes from client and ask question from SQL Server stored procedure, opens and closes a SQL connection after ending of question.
I've used this code:
using (var con = new SqlConnection(setting.ConnectionString))
{
try
{
//some codes (edited)
SqlCommand command = new SqlCommand(con);
command.CommandText = "procedurename1";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#name", sb.ToString()));
SqlDataAdapter adapter = new SqlDataAdapter(command);
try
{
adapter.Fill(dataSet);
}
catch (Exception ex)
{
con.Close();
con.Dispose();
throw ex;
}
finally {
con.Close();
con.Dispose();
}
}
catch(Exception ex)
{}
finally
{
con.close();
con.dispose();
}
}
I've used
netstat -a -n | find /c "1433"
to count SQL connections open and close.
Problem is SQL connections count increases and it rarely decreases and count down.
Main problem, is when my program works under lots of requests about 30 minutes, I get
SqlCommand timeout error (default 30 seconds passed)
and after restarting my C# program, the SqlCommand timeout will be gone.
Is this a problem of my program or SQL Server side?
Remember it always calls a stored procedure in SQL Server, not executing query
directly.
main method:
public void main()
{
Task.Factory.StartNew(() =>
{
allDone.Reset();
mySocket.AcceptAsync(e);
allDone.WaitOne();
});
}
public void e_Completed(object sender, SocketAsyncEventArgs e)
{
var socket = (Socket)sender;
ThreadPool.QueueUserWorkItem(HandleTcpRequest, e.AcceptSocket);
e.AcceptSocket = null;
socket.AcceptAsync(e);
}
public void HandleTcpRequest(object state)
{
//do some code and connection to SQL server
DLL.Request httprequest = new DLL.Request(dataSet.Tables[0], fileDt);
DLL.IHttpContext _context = new DLL.HttpContext(httprequest);
_context.GetResults();
}
Main problem, is when my program works under lots of requests about 30 minutes,
To isolate the root problem of the time-out, I suggest testing the sql query of the stored procedure independent of TCP socket calls for 30 minutes
and log the time-out exception details for inspection
Run the following query within 30 minutes to simulate your working environment:
public void RunQuery()
{
using (var con = new SqlConnection(setting.ConnectionString))
{
try
{
//some codes
}
catch(SqlException ex)
{
//test for timeout
if (ex.Number == -2) {
Console.WriteLine ("Timeout occurred");
// log ex details for more inspection
}
}
}
}
Read How to handle the CommandTimeout properly?
As you use async calls, I suggest you to try to use Asynchronous Database Calls With Task-based Asynchronous Programming Model (TAP)
I'm going to take a long-shot based on the way the limited Sql-related code we can see is written since we can't see "//some codes".
I'm going to guess that some of the disposable things like SqlCommand, DataReader, SqlDataAdapter, TransactionScope, etc are not in 'using' blocks, so are holding resources open on the database.
It may also be worth raising the possibility that this kind of problem could be in the code shown in the question or any other program accessing that database, including your own applications and SSMS (e.g. if a developer has an uncommitted transaction running in a window).
P.S. I would suggest deleting everything in the using block except the "//some codes" part.
UPDATE after more code was added
Here is your code after correction. this will ensure that the resources are disposed, which will prevent the leaking resources that are probably causing your problem.
using (var con = new SqlConnection(setting.ConnectionString))
{
//some codes (edited)
using (SqlCommand command = new SqlCommand(con))
{
command.CommandText = "procedurename1";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#name", sb.ToString()));
using (var adapter = new SqlDataAdapter(command))
{
adapter.Fill(dataSet);
}
}
}
P.S. don't ever write "throw ex;" from inside a catch ever again. It causes the stack trace to be lost - just use "throw;".
I got following error once in my application.
This SQLTransaction has completed; it is no longer usable
Stack Trace is attached below – It says about Zombie Check and Rollback.
What is the mistake in the code?
Note: This error came only once.
UPDATE
From MSDN - SqlTransaction.Rollback Method
A Rollback generates an InvalidOperationException if the connection is terminated or if the transaction has already been rolled back on the server.
From Zombie check on Transaction - Error
One of the most frequent reasons I have seen this error showing up in various applications is, sharing SqlConnection across our application.
CODE
public int SaveUserLogOnInfo(int empID)
{
int? sessionID = null;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlTransaction transaction = null;
try
{
transaction = connection.BeginTransaction();
sessionID = GetSessionIDForAssociate(connection, empID, transaction);
//Other Code
//Commit
transaction.Commit();
}
catch
{
//Rollback
if (transaction != null)
{
transaction.Rollback();
transaction.Dispose();
transaction = null;
}
//Throw exception
throw;
}
finally
{
if (transaction != null)
{
transaction.Dispose();
}
}
}
return Convert.ToInt32(sessionID,CultureInfo.InvariantCulture);
}
Stack Trace
REFERENCE:
What is zombie transaction?
Zombie check on Transaction - Error
SqlTransaction has completed
http://forums.asp.net/t/1579684.aspx/1
"This SqlTransaction has completed; it is no longer usable."... configuration error?
dotnet.sys-con.com - SqlClient Connection Pooling Exposed
Thread abort leaves zombie transactions and broken SqlConnection
You should leave some of the work to compiler, to wrap that in a try/catch/finally for you.
Also, you should expect that Rollback can occasionally throw an exception, if a problem occurs in Commit stage, or if a connection to server breaks. For that reason you should wrap it in a try/catch.
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
This is copied exactly from MSDN documentation page for Rollback method.
I see that you're worried that you have a zombie transaction. In case you pasted, it doesn't sound like you have a problem. You're transaction has been completed, and you should no longer have anything to do with it. Remove references to it if you hold them, and forget about it.
From MSDN - SqlTransaction.Rollback Method
A Rollback generates an InvalidOperationException if the connection is terminated or if the transaction has already been rolled back on the server.
Rethrow a new exception to tell user that data may not have been saved, and ask her to refresh and review
Note: This error came only once.
then it is very hard to say much; it could be simply that the // Other Code etc simply took to long, and the entire thing got killed. Maybe your connection died, or an admin deliberately killed it because you were blocking.
What is the mistake in the code?
over-complicating it; it can be much simpler:
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using(var transaction = connection.BeginTransaction())
{
try
{
sessionID = GetSessionIDForAssociate(connection, empID, transaction);
//Other Code
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
much less code to get wrong.
I use code below can reproduce this error, I use 1000 tasks to execute Sql, after about 300 tasks Successfully Completed, lots of exception about timeout error start to occur on ExecuteNonQuery(),
then next error This SqlTransaction has completed will occur on transaction.RollBack(); and its call stack also contains ZombieCheck().
(If single program with 1000 tasks pressure not enough, you can execute multiple compiled exe file at the same time, or even use multi computers execute to one DataBase.)
So I guess one of the reason cause this error can be something wrong in Connection, then cause the transaction error happens as well.
Task[] tasks = new Task[1000];
for (int i = 0; i < 1000; i++)
{
int j = i;
tasks[i] = new Task(() =>
ExecuteSqlTransaction("YourConnectionString", j)
);
}
foreach (Task task in tasks)
{
task.Start();
}
/////////////
public void ExecuteSqlTransaction(string connectionString, int exeSqlCou)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
SqlTransaction transaction;
// Start a local transaction.
transaction = connection.BeginTransaction();
// Must assign both transaction object and connection
// to Command object for a pending local transaction
command.Connection = connection;
command.Transaction = transaction;
try
{
command.CommandText =
"select * from Employee";
command.ExecuteNonQuery();
// Attempt to commit the transaction.
transaction.Commit();
Console.WriteLine("Execute Sql to database."
+ exeSqlCou);
}
catch (Exception ex)
{
Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
Console.WriteLine(" Message: {0}", ex.Message);
// Attempt to roll back the transaction.
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
}
}
}
Besides I find if I commit twice sequentailly will invoke this exception as well.
transaction.Commit();
transaction.Commit();
Or if Connection Closed before commit also invoke this error.
connection.Close();
transaction.Commit();
Update:
I find it strange that I create another new table and insert 500 thousand data to it,
then use 100000 tasks with select * from newtable sql, running 5 programs at the same time, this time the Timeout Error occur, but when transaction.Rollback() it didn't invoke the SQLTransaction has completed error.
but if the Timeout Error occur, jump into the catch block, and in the catch block do transaction.Commit() again, the SQLTransaction has completed error will happen.
I have experienced this error once and i was stuck and unable to know what is going wrong. Actually i was deleting a record and in the Stored procedure i was not deleting its child and specially the delete statement in Stored Procedure was inside the Transaction boundary. I removed that transaction code from stored procedure and got rid of getting this Error of “This SqlTransaction has completed; it is no longer usable.”
This message is simply because that you wrote code that throws an exception after the transaction has been already committed successfully.Please try to check the code you wrote after the Commit method or you can handle it by using Try..Catch and finally Blocks :) .
I built a parser that takes data stored in an xml file and sends it into a Microsoft Access database using linq-to-sql. I have the sql insert commands and they work... until they don't.
It's odd, I have each SQL command run (I keep them in a List and execute each command one at a time) and the first 40 or so run fine until they start hitting "unspecified error"s. The thing is, if I swallow the exception and instead have the exception catcher keep retrying, after a few seconds, they start working again. This means it's not an error of the SQL query itself (or at least how it's written).
This pattern repeats (there are thousands of inserts) many times. If I do normal exception handling, the program will just skip a few records while the error happens and keep inserting when whatever causes it temporarily goes away. if I let it run it's course, it inserts some records, skips some, inserts, skips, repeat and eventually inserts less than 2/3 of the records.
Is there any reason why my computer would only run 40 or so Inserts and then refuse to run more for a random but short interval?
I'm at a loss on what could be causing this.
The application is natively run; it does not use any server/web communication and all I found when looking for "unspecified error" pointed me to occurrences in ADO.NET applications.
Here's the code the error happens in:
public static string insertQuery(string sql)
{
string connetionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Documents and Settings\Owner\Desktop\Arbeit\TrademarkParserproject1\TrademarkParserproject\bin\x86\Debug\Database.accdb";
OleDbConnection connection;
OleDbDataAdapter oledbAdapter = new OleDbDataAdapter();
connection = new OleDbConnection(connetionString);
string success = "false";
try
{
connection.Open();
oledbAdapter.InsertCommand = new OleDbCommand(sql, connection);
oledbAdapter.InsertCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
success = ex.ToString();
return success;
}
success = "true";
return success;
}
Note, I have the application running in X86 mode to avoid errors with the ACE.OLEDB.12.0 adapter.
One thing that stands out, is you never close/dispose your SqlConnection. OleDbDataAdapter is also disposable and should be disposed. A 'using' statement is a convenient construct here:
public static string insertQuery(string sql)
{
string connetionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Documents and Settings\Owner\Desktop\Arbeit\TrademarkParserproject1\TrademarkParserproject\bin\x86\Debug\Database.accdb";
using(var oledbAdapter = new OleDbDataAdapter())
using(var connection = new OleDbConnection(connetionString))
{
string success = "false";
try
{
connection.Open();
oledbAdapter.InsertCommand = new OleDbCommand(sql, connection);
oledbAdapter.InsertCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
success = ex.ToString();
return success;
}
success = "true";
return success;
}
}