Transactions and Compensation Using BizTalk Server
After reading Charles Young's fantastic post today on BizTalk transaction compensation, I was finally inspired to write a post that's been on my blog "to do" list for 7 months. Specifically, I wanted to demonstrate simple compensation handling, and dealing with loops and transactions.
I'd like to walk through a simple solution I just built and demonstrate the transactional considerations. The first thing to show here is that data (variables, messages) manipulated within an atomic scope do NOT have their changes committed unless the atomic scope successfully completes. In the picture below, you'll see a very simple orchestration I built that receives a message, sets a value for a variable ("Status"), jumps into an atomic transaction, does a calculation, updates the "Status", and finally completes by writing the "Status" value back out. Basically what I'm trying to show is that the variable "Status" may have gotten changed by the action in the atomic scope, however, if the scope fails for any reason, that change isn't committed.
I'm using the (now-Microsoft) tool DebugView to view the Debug.WriteLine statements embedded in my orchestration. When I pass in a simple message, you see here that indeed the value is initialized ("Starting") and changed by the atomic transaction ("Updated").
If I pass in a bad message (in this case, dividing by 0), then the orchestration is suspended and the compensation code does NOT fire. Why? Compensation only fires for committed transactions, and since an operation within the atomic scope failed, there's technically nothing committed, so nothing needs to be compensated. Now what if I wrap the atomic transaction in an long running (LR) transaction so that I can catch any exceptions and gracefully handle it?
Now, when I run this process, the exception block catches the error, and I continue on in my orchestration. As you'll see here, because the atomic transaction did not commit, the "Status" field change was not persisted.
What happens if we instead cause an exception AFTER the atomic transaction has completed?
You'll see here that the step following the atomic transaction raises an exception. What do you expect to happen when I drop a standard (valid) message into this orchestration?
The compensation code did NOT fire since I didn't do anything to trigger it. All that happened was that the shapes in the Exception block were processed. Let's force a compensation to happen. We could, in the Exception block, use a Compensation shape and explicitly compensate the atomic transaction. But, what if I had 4 atomic transactions in there and didn't want to explicitly roll back each? What I can do is compensate the Long Running transaction, which in turn will execute the compensation code for each contained transaction in reverse order. We'll see more of that in a second. My compensation now looks like this:
If I spin up the orchestration now, you can see here that the Exception block AND compensation code both fire. Sweet.
What happens if I add a second atomic scope to our LR transaction and raise the exception after the new transaction?
Without changing anything in the LR transaction, it went ahead and executed compensation on both transactions in reverse order.
The last thing I want to show here (and probably the neatest), is something Charles mentioned in passing in his article. I like to show this when I teach BizTalk workshops and it always amuses folks. What happens if I'm executing transaction in the confines of a loop? Is BizTalk actually smart enough to keep track of this and handle it appropriately? I've modified my orchestration to now contain a Loop shape and cycle through 5 times. On each pass, it executes the atomic transaction. Following the loop, I raise an exception. I still haven't changed anything with regards to compensation in the LR transaction.
Any idea what you'll see when I run this? As you'll notice below, it goes ahead and executes each transaction, and exception is thrown and caught, and each of the looped transactions have their respective compensation code called. Neato. I'm always impressed to see that.
There you go. Read Charles' article for significant more depth on the topic, but hopefully this provides a more simple take on a fairly complex process.
Technorati Tags: BizTalk
Comments
Anonymous
December 08, 2006
I know it wasn't the point of your blog, but it's funny you talked about the DebugView from "Windows" SysInternals since I just started using that myself (thanks to a suggestion from the BizTalk troubleshooting guide). It's quite the life saver at times!Anonymous
June 04, 2007
流程intg_i=0; intg_k=0;Messagemsg; receive(msg)scope{