WorkflowQueueNames

As I wrote in my last post, I’m doing a bunch of WF related work. I’m close to releasing some WF related stuff I started building last week in Jon’s class. But I discovered something cool about the way WF’s queuing system works, and wanted to blog about it.

Side note - Speaking of Jon, he’s joined the “WF is not a toy” conversation. He had an interesting point about the persistence service that I hadn’t thought of. If you use the SQL persistence service and you have TransactionScope in your workflow, you end up with a distributed transaction, even if these are all writing against the same SQL instance. That’s a good enough reason to write your own persistence service right there.

In the WF stuff I’m building, I need a way for the WF runtime to notify a given workflow instance when something happens. WF has a low level queuing system as well as the higher abstraction data exchange system. I’m more interested in low level knowledge of WF, so I decided to use the queuing system.

In my implementation, the workflow instances only need to be notified when specific events happen. That is, I’m not passing in any real data on the queue – the arrival of the data is what’s important, not the data itself. Queues are identified by name and I started by using a simple string as my queue name. However, the queue name isn’t limited to be a string, it supports any IComparable class. This turned out to be a huge advantage for me.

Things worked fine when I was building a simple sequence, but when I moved to a parallel activity things went south. Since I was using a simple string, I ended up creating two queues with the same name, which didn’t work out well. Furthermore, I have two different notification situations. So I needed a way to have a unique queue name for the same activity type in parallel branches of the workflow as well as supporting two different notification situations.

Because queue name is IComparable instead of a string, I was able to create two queue name types – one for each notification situation. Each of these queue name types includes a string that I initialize to the activity’s qualified name, which as per the docs is “always unique in a workflow instance”. So I was able to kill two birds with one stone – supporting multiple parallel activities as well as multiple notification scenarios. That’s pretty cool. If they had used simple strings, I would have had to have a naming system like “notificationscenario:notificationdata:activityname” and then have to parse out the queue name string. In fact, I started down this path before I remembered that queue name is IComparable. Using IComparable is much much cleaner.

WF Clarifications and Corrections

Last week, after I posting my WF learnings, I got a call from Paul Andrew, Technical Product Manager for WF. Seems calling the built-in persistence service and the built-in web service support “toys” created some extra work for Paul. He blogged a response and I wanted to follow up on a few things here.

  1. The “toy” SQL Persistence Service – My understanding about how the built-in persistence service works was incorrect. As per Paul’s blog, “The WF runtime doesn’t load all idle instances on startup, that would be crazy.” Of course, we’re talking about the SQL Persistence Service, not the WF runtime, but it’s still crazy. It’s so crazy that when I thought that’s what the SQL Persistence Service did, I called it a toy! So I’m flat out wrong on this one. Sorry about that Paul (and the rest of the WF team).

  2. The “toy” Web Service Integration – Apparently, I was also mistaken about the use of ASP.NET sessions. But I was right about WF’s use of ASMX, the use of the tempuri.org namespace, and that web service support is limited to WS-I basic profile request/response style services. So while “toy” is a bit harsh, the web service integration is still pretty light weight. Where’s the WCF integration? I understand the need to support ASMX, but no WCF means no support for duplex conversations, either as service provider or consumer, and no support for reliable sessions. That makes WF’s web service integration a non-starter in my project. Of course, the good news is that you can build your own WF activities, so I can toss the built-in web  service activites and still get to keep the rest of WF.

  3. Is WF itself a “toy”? Paul has a list of reasons why WF isn’t a toy, including some silly ones (it wasn’t in Toy Story). In case there’s any confusion about my opinon of WF, let me be clear: I think WF rocks, full stop. My negative comments about WF were isolated to the two areas listed above and not intended to apply to WF as a whole. The other seven points were all about cool things that I didn’t realize WF does.

I’m not just trying to kiss up to Paul here – WF is one of two foundation technologies that my project absolutely depends on. (Any guesses on the other?) With the class out of the way and a better understaning as to what’s possible with WF, I will be diving much deeper on WF in the future. Watch this space for more WF related posts.

More Stuff I Didn’t Know About WF

  1. All communication from the host to the workflows goes thru the WorkflowQueuingService. Unlike other WF services, the queuing service is not replaceable. Communication from a workflow activity instance to the host goes thru some other service. There is no “default” activity -> host communication service, though WF ships with the ExternalDataExchangeService. You have to manually add the ExternalDataExchangeService to your workflow runtime instance. WF also includes the wca.exe utility which generates strongly typed HandleExternalEvent and CallExternalMethod activities for your workflow. And according to Jon, the External Data Exchange system was added specifically for SharePoint.

  2. The built-in sequential and state machine workflows are customizable. So if you wanted to have a custom designer or validation experience for an otherwise standard sequential or state machine workflow, you can inherit from the standard workflow type and add the custom validation and / or designer support. For example, as I wrote earlier, you can load a workflow from XAML. XAML workflows can’t support the Code Activity. So if you wanted to use the standard sequence designer but disallow the use of the Code Activity, you wouldn’t have to rewrite the sequence activity from scratch.

  3. You can execute workflows across a farm, similar to how you build a web farm. Workflows that get persisted to the persistence service can be loaded on any node in the farm. Of course, like web servers in a farm, you’d have to have the same bits installed on all the machines in the workflow farm. Sounds like an opportunity for something like Application Center for WF.

  4. The built in SQL Persistence Service is a toy. When you start your workflow engine, the SQL Persistence Service will auto-load all the existing persisted workflows into memory, as an “optimization”. So if you have thousands of order workflows persisted in your database and you decide to bring another workflow processing node online, that new workflow processing node will happily load ALL of the outstanding orders that it can find in the database. This service should have been included as a sample like the file based persistence service sample rather than described as “a fully functional persistence service” in the docs.

  5. WF Web Service integration is also a toy. WF leverages basic ASMX for all it’s web service integration, so your only choice for web services – consuming or exposing – is atomic request/response style services. You can have a workflow with multiple operations, but the default ASMX hosting infrastructure squirrels the WF Instance ID in the ASP.NET session, which will time out in twenty minutes (by default). Furthermore, the built in ASMX workflow host doesn’t provide an option to specify the web service namespace, so it ends up with the default http://tempuri.org namespace. Again, like the SQL Persistence, this should have been included as a sample, not included in the standard activities.

  6. Activities can generate code. In the previous item, I mentioned there’s basic ASMX hosting integration for a workflows. Turns out the WebService Activities generate that hosting code as part of the workflow compilation process. So in other words, if you add a WebService activity to your workflow, the activity will inject the custom ASMX hosting code into your compiled workflow. In this WebService activity case, the injected code isn’t very good, but the fact you can do this at all is very cool.

Logjam Worsens

Last week, I wrote about the college football logjam. While we’ve seen one team fall out of the running, the overall race for the #2 slot has tightened significantly. Last week, Auburn and USC held a small yet significant advantage in the voting over West Virginia, Florida and Michigan. This week, that margin is gone. Auburn’s loss combined with SC’s wholly unimpressive win (spoken as an SC alumni) over the Huskies and Florida’s impressive win over #9 LSU creates essentially a four way tie for second place. Only 100 votes separate #2 from #5 in both the AP and USA Today polls.

There are also a few other undefeated teams in the top 25: #7 Louisville, #19 Missouri, #20 Boise State and #24 Rutgers. Baring significant upheaval in the polls, only Louisville really has a shot to join the group at the top. They play West Virginia in a few weeks, so the winner of that game will likely stay in the hunt for the BCS title game. And Ohio State still plays Michigan at the end of the season, so we’re still looking at a maximum of four unbeaten teams.

As bad as this scenario is, it’s even worse to consider what happens if all these unbeaten teams lose. Currently, Texas, Tennessee, Notre Dame, California, and Auburn are all essentially out of the hunt. As long as there are at least two unbeaten teams, really none of these teams can legitimately argue that they deserve a shot at the title. But you can bet that ranked one-loss teams will be highly-motivated to beat ranked no-loss teams in order to be able to make a case for inclusion in the title game. USC plays #18 Oregon State, #10 Cal and #9 Notre Dame. Florida plays at Auburn and Georgia. Michigan plays Iowa (not to mention #1 ranked Ohio State).

If I was a betting man, instead of an Trojan fan, I would bet the BCS title game would be between West Virginia and the winner of the Ohio State / Michigan game. Obviously, if SC plays Notre Dame the way they played against Washington, they’ll lose. But SC will be amped to the max for Notre Dame, so I would be more concerned about SC looking past Oregon State or Cal the way they obviously didn’t take Washington seriously. By the same reasoning, I figure Auburn has a better-than-decent chance of beating Florida next week. If SC and Florida lose, that leaves three unbeaten teams, two of which play each other. Hence my prediction.

Of course, I’m not a betting man, so I’m hoping to see the winner of Ohio State and Michigan play USC for the championship. Note I wrote “hoping” which is code for “that’s only going to happen if they play better than they did the past two weeks”.

Cool Toy From the Teacher

As I wrote this morning, I’m in training this week. The instructor (who I wrote earlier is “pretty good”) is Jon Flanders. I didn’t recognize his name, but I did recognize his Atlas based WF Designer that he released a month and a half ago or so. It’s a cool piece of work so it’s doubly cool (for me anyway) that he’s teaching this class.