Jim @ imason

Internet Architect by day, environmentalist by night: Jim Schwartz @ imason.

Rehydrating a State Machine Workflow

  • Comments 3

At first glance, Windows Workflow does a good job of persisting workflows to the database for long-running State Machine Workflows.

However, what happens when you update your workflow assembly? Windows Workflow will try to retrieve the workflow from the SQL Persistence store and de-serialize the object, but it will throw an exception (You’ll see a SerializationException or IndexOutOfRangeException).

There are different ways to handle this situation. The first (and most obvious way) is to set versions on your DLLs so that the workflow will de-serialize into a previous version of a workflow and continue running in the older version. But what if the change you made to the workflow fixes an important bug in the previous version? In this case, you may want  your previously persisted workflows to use the new version of the code.

A few quick Google searches will lead you to a few different options in handling this situation:

  • Using an assembly resolver or using the “AppliesTo” attribute [1]
  • Dynamic Workflows [2]
  • Breaking up into smaller workflows [3]

None of these options are particularly appealing to me, so I had to find a better way to handle updates to the workflow code but still allow my long-running workflows to operate.

My “outside the box” solution: Workflow Rehydration

To achieve Workflow Rehydration, I’m keeping track of the current state in a SQL database and if the current workflow can’t be de-serialized (because the workflow has been updated), I instantiate a new workflow and I set the state to the state it was previously in.

The obvious concern that comes up using this approach is “how do I avoid executing the code inside my StateInitializationActivity?

To get around this issue, I’m passing in a boolean parameter into my State Machine workflow that indicates whether or not the workflow is being rehydrated. I then use an IfElseActivity to execute my State Initialization code only if the workflow is not being rehydrated.

image

The end result is that the workflow goes back into its previous state, but it’s now running inside the new updated workflow code. You might call this a “Utopia State” (Apologies for the lame pun).

The end user has no idea that the workflow has gone through this transformation from an old version of the workflow code to the new version; and it only took a little bit of code along with some IF conditions.

References: 

[1] http://msdn.microsoft.com/en-us/library/aa349375(VS.85).aspx

[2] http://community.bartdesmet.net/blogs/bart/archive/2006/08/28/4322.aspx

[3] http://www.sitechno.com/Blog/WorkflowVersioningOfLongRunningProcessesSucksHereIsMyTakeOnIt.aspx

Leave a Comment
  • Hello!

    Very Interesting post! Thank you for such interesting resource!

    PS: Sorry for my bad english, I'v just started to learn this language ;)

    See you!

    Your, Raiul Baztepo

  • hi,

    I have created the sample state machine workflow in asp.net by VB code, with two states. the first state has state initialization and event driven activity, and the second state has state initialization. when start the workflow, it works fine at the initial state. when i raise a event using the handle external event activity it doesn't move to next state.

    I know that i have made a mistake, but couldn't able to trace. could you help me.

    here is the code

    <ExternalDataExchange()> _

    Public Interface ICodeset

       Event Add As EventHandler(Of ExternalDataEventArgs)

       Sub PageGoTo(ByVal args As CodesetEventArgs)

    End Interface

    <Serializable()> _

    Public Class Codeset

       Implements ICodeset

    Public Event Add(ByVal sender As Object, ByVal e As System.Workflow.Activities.ExternalDataEventArgs) Implements ICodeset.Add

    Public Sub OnAdd(ByVal instanceId As Guid)

            Dim args As New ExternalDataEventArgs(instanceId)

           RaiseEvent Add(Nothing, args)

    End Sub

    End Class

       Protected Sub btnAdd_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAdd.Click

           Dim instance As WorkflowInstance

           instance = workflowRuntime.CreateWorkflow(GetType(WorkflowLibrary.Codeset))

           instance.Start()

           Session("InstanceID") = instance.InstanceId

           RunWorkflow(instance.InstanceId)

           Dim str As String = instance.InstanceId.ToString

           RunWorkflow(instance.InstanceId)

           objCodeset = New DataAccessLayer.Codeset

           objCodeset.OnAdd(instance.InstanceId)

           RunWorkflow(instance.InstanceId)

       End Sub

    Thanks in advance

    Venkatesh

  • What about StateFinalizationActivity in Initial State and StateInitializationActivity in TargetState (RestoringState)? It means you must add IfElseActivity in all StateFinalizationActivity and StateInitializationActivity.

    I think applying dynamic update is better solution.