Friday, August 29, 2008

Compensatable transactions

Up until now, when working with SQL Server, the most common transaction type I’ve used was the XA-style transaction. An XA transaction involves the XA protocol, which implements the two-phase commit (you’re probably familiar with this, most DBMS use it, but if you aren’t I suggest you go ahead and work on this issue, since it is essential when working with databases). The XA transactions, when using non-volatile resources, guarantees the ACID properties (Atomicity, Consistency, Isolation and Durability). This is all done at the DBMS level.

However, Windows Workflow Foundation “translates” this idea into an activity: the TransactionScope activity. What this means is that the activity knows how to use this kind of transactions without forcing the programmer to explicitly open a transaction. You just place activities inside the TransactionScope activity and that’s a XA-style transaction. You can even define the isolation level of the transaction for that activity (Serializable, Read Uncommitted, Repeatable Read and so on).

But WF also has another transaction style: The compensatable transactions. I wasn’t aware of this type of transactions up until now. The idea is basically the same as in XA-style transactions: if something goes wrong in one of the operations performed in the scope of the transaction, the data must go to a consistent state. But there’s a difference: When using XA-style transactions, if something fails, the transaction is “rolled back”. When using compensation, if something does fail, the transaction isn’t automatically “rolled back”. Instead, you must provide the actions to compensate the failure. To better explain, let me use the example given by Kenn Scribner: “If I give you five apples using a XA-style transaction and the transaction fails, time itself rewinds to the point I started to give you the apples. In a sense, history is rewritten such that the five apples were never given in the first place. But if I give you five apples in a compensated transaction and the transaction fails, to compensate (so that we maintain a determinate application state), you must return five apples to me.”

What this means is that the programmer is responsible for compensating, providing the actions to compensate the failed transaction. There is no “rollback”. Is this better than XA-style transactions? Well, it certainly gives you more control (and responsibility), but you must be very careful when writing compensation actions. The smallest mistake can leave a database in an inconsistent state.

I haven’t used this transaction style yet, but Kenn Scribner gives a hint on a few scenarios where it could be more useful then the XA-style transactions. I’m going to analyze these scenarios more deeply in order to see if it really makes sense.