问题
My current understanding of transactionscope timeouts.
If a transaction has been running longer than the set timeout time it throws an exception when transaction.complete() is called. So if the processing within the transaction has been going on for X minutes we still would have to wait X minutes after which the transaction.complete is called.
In our case, we are using transactionscope from within a webservice - the end user of the web request will have to wait for X minutes before the transaction is aborted and the exception bubbled back.
However, the default timeout for a HttpWebRequest is 100 seconds (according to msdn). Since the client times out in 100 seconds we have a timeout in transactionscope of a minute. This ensures database consistency.
Is my understanding of timeouts correct?
Question: We would like to minimize the time it takes for the end user to know the results of the transaction. To minimize latency we decided to split up the code using nested transactionscopes - each with a timeout of say 15 seconds. If a child transaction is taking longer than a 15 seconds we abort the transaction as a whole.
Here it seems that the child transaction's timeout is ignored. I get an exception only after the parent transaction's timeout is called. In the following code ChildTransaction() always returns true. What is the recommended approach to minimize the latency? The code shows default timeout of 1 minute just so the code is cleaner
internal bool RootTransaction()
{
using (TransactionScope transaction = new TransactionScope())
{
try
{
bool result = ChildTransaction();
//The result is always true.
if (!result)
return result;
for (int counter = 0;counter <= 10;counter++)
{
//Either sleep OR do some processing
System.Threading.Thread.Sleep(5000);
//
//Dosomeprocess()
}
transaction.Complete();
return true;
}
catch (Exception e)
{
return false;
}
}
}
internal bool ChildTransaction()
{
using (TransactionScope transaction = new TransactionScope())
{
try
{
//Sleep for 70 seconds
System.Threading.Thread.Sleep(70000);
transaction.Complete();
}
catch (Exception e)
{
return false;
}
}
return true;
}
回答1:
Try to look at it this way:
The length of the transaction is only determined when you call trans.Complete() or exit the transaction scope. Take the following code:
using (var trans= new TransactionScope())
{
Threading.Sleep(99999);
trans.Complete()
}
There is no way to throw a timeout exception while inside the sleep routine and it wouldn't make sense if it did. And so using transaction timeouts (this way at least) can only guarantee that if the transaction takes longer than your timeout, it will not be commited.
If you are just executing one query (which I wouln't know what you use the transactions for) then you could set the query/command timeout (or whatever you call it). IIRC, your query will return immediately after the timeout expires.
Another way would be to set your web service request timeout and just assume that the webservice is taking too long to respond because of whatever was inside your transaction.
EDIT: You could try:
- Spawning your transaction on a different thread and then wait for it to complete (using Thread.Join(timeout)) on your main thread (one used by the webservice call). So if it doesn't terminate before the timeout you specified then you could stop waiting and return a timeout error (dont forget to signal the other thread to abort the transaction).
- Assuming you are only performing SQL queries inside those transactions, you could use the "BEGIN TRANSACTION" keyword to specify the transaction in the sql script (hacky indeed). Then you could just specify the command timeout and execute all this in a single line of code. But then this requires you to move everything you do inside the transaction into a sql script which may or may not be possible for you... and it isn't clean.
来源:https://stackoverflow.com/questions/10055491/understanding-transactionscope-timeouts