Friday, January 9, 2009

Smart Clients and System.Transactions Part 2 - Timeout

This is the second installment of an ongoing series about using System.Transactions as the fundament for client-side infrastructure for managing changes among loosely coupled components.

Previous posts:
Introduction


Pop quiz: How long before the transaction times out here:

var scopeTimeout = new TimeSpan(
0, // Days
2, // Hours
0, // Minutes
0); // Seconds
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
scopeTimeout))
{
// Do some work
scope.Complete();
}


You might be tempted to answer 2 hours, however it's impossible to say with the information I've given you here. The correct answer is probably 10 minutes. As described here and here, there are settings in the configuration that override whatever the programmer has set, and the setting with the final say is in machine.config. So the 100% correct answer is that the timeout will vary from machine to machine and application to application, and in order to determine the timeout you would have to examine the code, app.config and machine.config on the given machine.



As an aside, the API for the constructor of TransactionScope here leaves a lot to be desired, don't you think? As pointed out by Alkampfer in the comments here, the API communicated by the constructor here violates the principle of least surprise.



What does the official documentation for the constructor of TransactionScope have to say? Well, this:



Initializes a new instance of the TransactionScope class with the specified timeout value, and sets the specified transaction as the ambient transaction, so that transactional work done inside the scope uses this transaction.



No mention of all this business with the configuration. I don't know about you, but I read this basically as a confirmation of what I already "knew": the timeout is what I decide and supply in the constructor. Even the Microsoft technical writers thought this one was a no-brainer, I guess.



How should Microsoft fix this problem? Update the documentation for a start. I think it might be a good idea if the logic in the constructor checked whether the supplied timeout was larger than what the configuration allows, and that an exception was thrown if this was the case.



Yet another aside: this kind of problem with timing almost always lead to problems that go undetected by both developers and testers, but that blow up in the face of the end users almost immediately. It's a conflict of interest between the developers and testers on the one hand, and the users on the other. More precisely, everybody wants to get their work done as quickly as possible, but they don't do the same work. For a start, the developer tests the code by means of automated tests which for the most part run much quicker than any timeout. And when the developer/tester tests the application by hand, he or she is not interested in the work done by the application, but in getting the testing done. The end user on the other hand, actually uses the application.



Anyhow, this puts me between a rock and a hard place. My application is running client-side, and I can't get my hands on the machine.config on all these machines. And the users of my application do a lot of fact checking while it is "in transaction"; they read documents, make telephone calls, talk to colleagues, and so on. They spend time, and this timeout issue amounts to a serious bug rendering the application close to unusable for some of the users.



So, how did your brave correspondent get around this serious setback? I'll come to it at the end of this series. I just have to explain some other stuff first. Hang in there!

No comments:

Post a Comment