Versioning WF Flows

by mgordon 17. June 2008 12:58

I posted, previously, about my foray into Windows Workflow.  In that post, I described a bit about the application I was writing and how I was using Workflow to solve the problem of moving orders through various business processes.

Well, the application is maturing and I recently deployed an update to the original flow definitions and everything ground to a halt.  I was aware of the versioning issues, thought I had it covered, but I didn't.  Before I delve into the details, I want to say that while I find the current story around versions of flows to be lacking in many ways, I honestly can't think of a better solution to the problem.  That said, the approach reminds me a bit of the versioning of COM interfaces in the good old days.

The problem goes something like this...I deploy a version of my flow (say version 1) and I start sending items down the flow.  These are long running processes, so I'm using the persistence service and database to store the state of my flow instances as needed.  At any point in time, I have several instances at various states of completion with state stored in the database.  I decide I need to change one of my flows and replace version 1 with version 2, of my code.  Now, all the instances that were in my persistence database that were expecting to run on version 1 of my flow are stuck.  There is a strong affinity between a persisted instance and the version of code it was started on because the version of the code is part of the persisted state.  Also, the state of each activity in the flow is persisted.  If I've added, removed or rearranged any of my activities, the state will no longer fit into the flow when it's dehydrated.  If an attempt is made to continue the a flow from version 1 on the version 2 code base, the result is an odd index out of bounds exception.

I did a lot of searching to find a solution to this problem and no where did I find the complete solution.  After piecing it all together and doing some experimentation, I finally hit on the secret sauce.  The only mention of this problem, that I could find on MSDN was here and mentions only that .Net versioning practices should be employed.  So, being the bright guy that I am, I proceeded to generate a key pair (using SN.EXE), marked my project containing the flows as being strong named and associated it with my key pair for signing.  The objective, here, is to be able to keep all versions of your flow around.  So, I GAC version 1 and also version 2.  The workflow engine is smart enough to discern which version the instance should be loaded back in to.  I understand this approach and it seemed to me it would work, but it didn't.

If you're using persistence and not using a timer, you must be firing events into your flow to get it to continue after it's been persisted.  To do this, you need to use the External Data Exchange service.  You define an interface that contains the events that can be fired into the flow - and another for events the flow can fire out to your host.  You then create classes that implement the two interfaces ad register them for use.  In my implementation, I had events going both ways.  After deploying both versions of my flows, I tried to fire an event to an existing instance.  This produced an exception stating that the event could not be delivered because the queue had not yet been created.  WHAT???

The problem here was how I had my classes grouped into projects.  I had my flows and External Data Exchange interfaces defined in the same project which meant that I could not version my flows apart from the interface.  While I have not found documentation to back it up, my suspicion is that regardless of what versioning tactic you use, a new version of the interfaces will not be tolerated.  The only solution to this is to move the interfaces and the code that implements them into a separate project and never touch the version number for it.  After rearranging my classes and projects, I was able to start instances, allow them to persist, deploy an addition version of my flows and continue the previous instances.

The bottom line for me was that I had to make such deep changes to my workflow code, that some of the existing instances had to be thrown away as unusable.  The moral, here, is to make sure you have a correct versioning strategy in place from the get-go or risk losing data later on.

Before closing I wanted to mention that I did see mention of folks being able to actually hack the persistence database records to recover from this situation.  This is not for the faint of heart and was definitely not for me.  You can find some instruction, out there, on how to do this but do it at your own risk.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Workflow

Workflow Services and the DTC

by mgordon 7. February 2008 10:56

As noted in a former post, I implemented a change order system using Windows Workflow.  Recently, the system was deployed for User Acceptance Testing and odd things began to happen.  The system is using both tracking and persistence services and what we observed in the Sql Profiler was that the Sql to insert the persistence record was never making it to the database, but the tracking was working fine.

I implemented a handler for the ServicesExceptionNotHandled event on the WorkflowRuntime object, but nothing was being raised.  After a couple of hours poking and prodding, I finally linked the problem to the windows firewall.  If the firewall was turned off, everything worked as expected.  I spent some time researching the problem and found a couple of posts on the Microsoft Forums here and here that discuss the SharedConnectionWorkflowTransactionService.  Apparently, when the persistence and tracking data are in two different databases, the DTC gets involved any updates to the data and the firewall was blocking the DTC traffic. 

As mentioned in one of these posts, I combined the persistence and tracking databases into one, and added the SharedConnectionWorkflowTransactionService to runtime when I started up.  The combination of these actions removed the dependency on the DTC and all is working fine, now. 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

.Net | Sql Server 2005 | Workflow

WF First Impressions

by mgordon 29. November 2007 11:25

I've been working with a team since March on a huge, complicated billing and customer management system for a utility company.  Part of what the application does is manage change orders of various types.  Depending on the order's type, it is routed to various locations so that actions can be performed at each of them.  When this requirement was originally discussed, it was thought that it would be sufficient to define the paths the orders would go on, statically.  That is, the order of stops would always be the same.  These paths were allowed to branch, but there was no decision logic involved in them.  I looked at WF, at that time, and decided it would be overkill.  I then went about writing an engine to manage the process of promoting the orders through the paths which was a huge, messy task.

A few months later, it as decided that decision logic was, in fact, going to be needed in the flows.  I reasoned that I had two options at this point.  I could either go back into the engine code I had written and implement some polymorphic way to call business logic (such as coding the calls against an Interface and loading up a configured class that implemented the interface at runtime)...OR I could toss the engine and look at workflow, again.  I chose to do the latter.  I hadn't yet used workflow on any production application, so I armed myself with a couple of books (this one and this one) and dug in.

Now that this portion of the application is rewritten, I wanted to post about my take on the experience. 

Less Time and Code
First of all, I was extremely impressed at how much code I DIDN'T have to write for this implementation.  In writing my engine, I had to write a ton of code to determine whether or not the order was on a path parallel to the one I was currently processing and whether I could continue or not.  Having Workflow handle all that for me was a huge bonus. This also translated into a great deal of time savings.  I implemented several complicated flows and had a working system in about two and a half weeks with the previous engine I wrote taking a couple of months.

Expressing Complicated Logic in a Visual Way
I'm not sure why, but I kept thinking I was going to encounter a set of logic I needed to implement that I could not express with the supplied workflow activities, but I did not.  I didn't need to write any custom activities (although that would have been a good exercise to have had) in order to get the job done.  I found the activities that came in the box to serve me very well.

Along with the good, though, I did encounter a few things that I wasn't crazy about.

Inheritance and the Designer
As I worked through the various flows I had to implement, I kept encountering bits of code tied to code activities that they all the flows had in common.  Naturally, my instinct told me to refactor these, put them into one place, and share them.  So, I pulled all the common bits into a base class and inserted it into the inheritance hierarchy.  I created the base class and had it inherit from SequentialWorkflowActivity (the base class, by default, of a sequential workflow) and then modified my flows to inhert from this base class.  What I expected, was for the designer to recognize the inherited methods and allow me to tie my code activities to them.  However, the designer did not display any of these methods for me to choose from, and when I manually entered the method name it both insisted upon adding the method to the workflow again AND complained that it could not do so since the class it was inheriting from already had a method by that name.  I should mention that I was using VS 2005 for my development and have not tried to do a similar thing in VS 2008.  This may have been corrected.  Also, there may very well be a way to accomplish what I needed, but the way that seemed obvious to me did not work as I expected it to.

Communication Between Workflow and Host
All communication between the workflow runtime (within which your workflow executes) and the host of the runtime is asynchronous.  To communicate into the workflow, you need to fire an event into it and the workflow needs to be in a state of actively listening for that particular event.  For the workflow to communicate with it's host, an event is fired from within the flow and the host needs to have a handler for the event.  For some of my flows, it was necessary for the flow to occasionally ask the user how to proceed with a messagebox allowing a yes or no answer.  The amount of code to implement this was quite a bit more than I expected.  I understand that the workflow engine is running on a different thread and that all this communication needs to be synchronized, but I have to think that the API providing this functionality will be improved over time to make quicker work of implementing this type of communication.

You can expect that I'll be posting more details about workflow and my experiences with it along the way.  I'm reluctant to share too much at this point since I still consider myself to be a rank amateur with the technology in regard to best practices.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Workflow

Powered by BlogEngine.NET 1.1.0.7
Theme by Mads Kristensen

About the author

Name of author Mitch Gordon
Contractor specializing in .Net and other Microsoft technologies.

E-mail me Send mail

Recent posts

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2009

Sign in