- I find Jim Kobielus’ “SOA as 50 square miles of fungus” analogy funny and strangely compelling. The “keep in the dark and feed it shit” jokes practically write themselves. (via Joe McKendrick)
- Politics 2.0 Rising: The number of Americans who got “most of their information” about the 2006 midterm elections was double the number from the 2002 elections.
- Do you use external/flash drives? Do you have issues when you try to “Safely Remove Hardware” with said drive? I do, all the time. Apparently, unlocker is the answer. (via Paul Andrew)
- How come there’s no information about LogToTraceListeners in the WF documentation? As far as I can tell, it’s not in the Windows SDK docs at all and the only reference to it on MSDN is this year-old article and this year-old blog post. I only discovered because someone on the internal WF discussion alias asked about it. I’ve added In my SSB/WF work, I subclassed the built-in SQL persistence service in order to add tracing support. If you’re developing a WF host, you need to turn this on. I find it mind-boggling this isn’t included anywhere in the official WF docs.
- Nice to see Soma bragging about Software Factories. As he writes, our current solution – consisting of the Guidance Automation Toolkit and the DSL Tools - are really just a first step. I’m just starting to experiment with the Web Service Software Factory (WSSF). Aaron Skonnard introduces both the ASMX and WCF version in his two most recent Service Station articles.
- Michael.NET makes Programming Promises and Ted Neward swears the Oath of the Conscientious Programmer. Why stop there? How about the Architect’s Affidavit to actually implement the shit we draw on the white board? The Technologist’s Testimony of understanding and belief in all things geeky and gadget? Come on, isn’t this just called “doing your job”? Do we really need to make promises and swear oaths to take it seriously and do it to the best of our abilities?
Morning Coffee 19
Binding Across States in WF
I didn’t get much done today – recovering from the norovirus and all. But I did figure out an important point about State Machine Workflows.
For my SSB/WF prototype, I decided to implement my business logic as both as a sequential and state machine workflow. While everything worked fine in my sequential prototype, things started failing once I got to my second state. Turns out that I was trying to bind property values across states, which is a no-no. Since states may be entered more than once, they are executed in their own subordinate activity execution context. As per the State Activity docs, “the definition of the child activity in the activity tree (referred to as the template) is never executed and is always in the Intialized state”.
I’m fairly sure that when you try to property bind across states, you’re connecting to this template activity, rather than the activity that was actually executed. So instead of getting real data (in my case, the handle of a SSB conversation) you get whatever that value was set to in the designer.
Of course, once I figured out about the subordinate AEC, this behavior makes perfect sense. But it could be better documented. So far, the best information on them is in the Advanced Activity Execution chapter of Essential WF.
BTW, to deal with this, you need to promote the values that matter out of the individual activity instance up into the workflow instance itself. In the databind dialog box, there are two tabs: “Bind to an existing member” and “Bind to a new member”. I’m not sure why the WF dialog existing member tab is there for state machine workflow since it doesn’t do what you might expect it to. Instead, you should create a new member as I’ve done here. This creates a field or dependency property (whichever you choose) on the parent workflow itself, which is then available to all activities in all states within the workflow.
I wonder how this works with XAML only workflows? There doesn’t appear to be any way to declare a field or dependency property in XAML. The templates that ship with the WF SDK aren’t XAML-only, they’re a combination of XAML and code. When you create a new member, it’s always created in code. The idea of XAML only workflows is very appealing – it severely cuts down the surface area that can be meddled with in your host. But you still need to easily share data between activities!
Morning Coffee 4
Recurring 8am Friday meetings are not my style.
- I’ve been tracking WCF for a long time. Yet, it’s still a dauntingly large topic. Yesterday I spoke to a friend who works in Windows Live who is just beginning to learn about WCF and it’s literally overwhelming him. His reaction reminded me of my early reactions to COM. It feels like no matter how much you learn about WCF, the “pile” of stuff still to learn doesn’t shrink. In contrast, while my initial exposure to the .NET Framework was overwhelming, eventually I got to the point where I felt like I had a good handle on what was in there.
- With all the configuration settings in WCF, the number of valid combinations is astronomical. While WCF’s configuration based approach is arguably more flexible than a code based approach, it’s also more complex and harder to debug in my experience. Config debugging seems to be an endless cycle of tweaking the config file and running the app to see what the effect is. We need better tools than SvcConfigEditor.
- Responding to yesterday’s Morning Coffee, Jon Flanders confirmed via email that the built-in SQL WF persistence service “doesn’t recover from faults to the last good persistence point” and that “when a fault happens, the instance closes and…is removed from the persistence database.” Is this the right behavior? I’m thinking it depends on the workflow. More on this later.
- I’m trying to get my teammates to start using the Beyond Bullet Points approach to the various presentations we build as a team. Interestingly enough, it’s been easier to get my team to adopt an agile development methodology than to adopt the Beyond Bullet Point presentation methodology. I would have expected the opposite.
- The Caps trounced the Canadiens last night, ending a five game losing streak. I’m not that worried about the losing streak – the Caps have had several players out with the flu. But beating Montreal, who came into the game twelve games above .500, so badly is a good sign. And how about Nycholat? Two goals and four assists in seven games since he was called up from Hershey. Even more impressive, he’s +2 even though the Caps were 2-5 and outscored 24-18 in those seven games while averaging nearly 21 minutes of ice time per game. Here’s hoping Nycholat stays hot.
Morning Coffee 3
I’m living in a tinder box, hosing down the roof
It’s raging all around me, and I still refuse to move
There’s a lesson I’m desperate to learn
And I’m willing to burn
“Willing To Burn” by Maia Sharp
- A warm welcome goes out to the 110th congress. Between the Democratic majority in both houses and Republicans looking to distance themselves from President Decider and his abysmal approval ratings, maybe we’ll actually get something accomplished in the next two years.
- Not as nice as USC trouncing Michigan, but I like seeing Notre Dame on the receiving end of a 41-14 beatdown from LSU in the Sugar Bowl. That’s the 9th consecutive bowl loss for the Irish.
- Actually started getting some work done yesterday. Today I’m doing some WCF STS work, but yesterday I focused on SSB and WF.
- I need to better understand WF’s faulting and compensation model. I got sidetracked yesterday when I realized that when a WF instance faults, the built-in SQL persistence service deletes the persisted instance from the database. That doesn’t seem right to me, but I was wrong last time I called out the WF SQL persistence service so I want to do more digging before I open my trap.
- I dig WF persistence. I wrote a few weeks ago about shipping a WF instance to a developer for debugging. Yesterday, I thought about having a persistence service that kept a history of the WF instance rather than overwriting it. I wonder if that would help with production debugging?
- Great quote yesterday by my boss, speaking ill of a project that
will remain nameless:
“Basically, they’ve spent the last month building an executive presentation to say we’re screwed”
Transactions in Workflow Foundation-land
I’ve been spending some quality time with SSB and WF of late. On the balance, my opinion of both these technologies is very positive, though each has some warts of note. For Service Broker, they got the transactional messaging semantics right, but much of the lower level connection management – what SSB calls “routes” are clumsy to deal with. For Workflow Foundation, the execution model is amazingly flexible. Unfortunately, WF’s support for transactions is significantly more rigid.
If you’re build a SSB app, you’re typical execution thread looks like this:
- Start a transaction.
- Receive message(s) from top of the queue.
- Execute service business logic. Obviously, this varies from service to service but it typically involves reading and writing data in the database as well as sending messages to other services.
- Commit the transaction
When I sat down to marry SSB and WF, I naively assumed I could simply use WF for step three above. Alas, that turns out to be impossible. This thread on MSDN Forums has most of the gory details, but the short version is that WF does not support flowing host managed transactions into the workflow instance. As per Joel West in the aforementioned thread:
“[T]he WF runtime in V1 only supports flowing in a transaction on WorkflowInstance.Unload. There are various ways that you could try and hack this (with a custom persistence service or WorkflowCommitWorkBatchService) but if you do this it won’t work correctly 100% of the time and the times when it fails (error conditions or failures causing the tx to rollback) will be exactly when you are expecting transactional consistency.
Bottom line – the only way to make this work is to call WorkflowInstance.Unload inside your transaction scope. This was the best that we could do in V1 to try and enable this pattern in some form. Not always ideal but it can be made to work for most scenarios that require usage of an external transaction.”
So the WF compatible execution thread looks like this:
- Start a transaction
- Receive message(s) from the top of the queue
- Load/Create the associated workflow instance for the received messages
- All messages received are guaranteed to be from the same SSB conversation group, which is roughly analogous to a WF instance, so this turns out to be fairly easy
- Enqueue the received message in the workflow instance
- Unload the workflow instance
- Commit the host transaction
- Reload the workflow instance
- Run the workflow instance (note, I’m using the manual scheduling
service)
- Workflow instance creates a transaction if needed
- Unload the workflow instance (typically done via UnloadOnIdle in the
persistence service)
- Assuming the workflow instance needed a transaction, it gets committed after unload
Basically, you use two transactions. One host managed transaction to move the message from SSB to WF instance and one WF managed transaction to process the message.The need for two transaction instead of one is unfortunate, but required given the current design of WF. And frankly, given the importance and difficulty of transaction management, I’m not that surprised that WF has hard coded transaction semantics. Trying to build a generic transaction flow model that would work in the myriad of scenarios WF is targeting would have been extremely difficult. At least there is a work around, even if it means using two transactions and loading and unloading the workflow instance twice.
However, there is a silver lining to the two transaction approach: two unexpected benefits when dealing with poison messages. First, SSB doesn’t have dead letter queue like MSMQ does. Moving a poison message to a dead letter queue would break SSB’s exactly once and in order semantics.(MSMQ doesn’t guarantee in order delivery) But moving all messages into the WF instance gets them out of the main SSB queue so poison messages don’t continue to get processed over and over.
Second, because the workflow instance is peristed after the messages are enqueued, there’s a representation of the workflow after the message is received but before the message is processed. If there’s a poison message, attempting to processing the message will fail and rollback to this state. This persisted workflow instance could be sent to a developer who could step through it to determine the cause of the error. We could even have developer versions of runtime workflow services so we could read remote data and simulate data updates. I wouldn’t want the developer updating production data in this way, but it would be great for troubleshooting issues.