In this installment we will look at the persistence functionality built into the workflow framework. But why is persistence important anyway? You have to remember that workflows represent processes and these processes can be short or long. If all process were short and completed in a few seconds life would be much easier and we would not need to persist, but processes tend to be long running and to make best use of resources in this case we need to be able to offload (persist) those workflows that are not doing anything right now.
Persistence is not just about long running processes, although that is one of the most important reason, its also about saving state during intermediate states so that a recovery can be made if a failure occurs. Other uses could simply be resource optimization or to save a workflow in one application and then load in another, sort of a travelling process between applications.
As we saw previuosly that there is a distinction between the runtime and the services a workflow can use which gives us the flexibility to easily plug-in and out these services. Persistence is also used in similar fashion. A ready-made persistance service is the SQLWorkflowPersistenceService, which uses SQL Server as the backend store. Let's now see how we can use this service.
First thing to understand is that workflows don't persist themselves, they have to be persisted by the host application which has access to the workflow instance object. To simulate the process we are going to create a workflow application along following lines:
- A workflow that counts to ten
- The workflow call the host during the counting and asks to be persisted
- The host unloads the workflow and waits for a user input to reaload it so that it can contiue its counting process from where it left off
First step create a workflow that counts to ten and calls a host function at an arbitrary value, lets say 6:
Now the function called by this workflow is just setting an event, we will use this to trigger the code in the host program.
How does the host code interact with it? Here you go.
We put a wait on the event we defined in the PersistManager class, which is then set when the workflow calls the function. This leads the host to unload it and once the user input arrives it loads it back up.
I described the whole process but did not mention the actual persistence part yet, let's look at it now. Since we are using SQL Server as our backed database we need to set it up first. For the SQLWorkflowPersistenceService it needs two tables in the database, the schema for which is provided as an sql script that you can find in C:\<WINDOWS DIR>\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\<LANGUAGE DIR>. Open the script from here, create a new database in SQL Server called let's say WFPersistence and run this script in it. You should have tables InstanceState and CompletedScope in it. The InstanceState table is used for storing the workflow instances and the CompletedScope is used for storing the activities executed during a transactional workflow. Another script needs to be executed which creates the stored procedures needed for persistence serivce, it comes with a _logic in it.
Now let's add the persistence service to the runtime so that all persistence calls can be passed to it.
This is it. Now run the workflow.
At this point go to the database and open the table InstanceState, you should see the persisted instance.
When we press the key it gets loaded back and resumes it work as planned.
and the workflow is removed from database.
Did you notice the second "Workflow persisted" message at the end? I had put a handler on the persist event of the runtime like so:
Why did it persist the second time? Actually it has to do with how the workflow runtime defines its "persistence points". These are places during the executing when the workflow would be persisted. They include:
- When workflow becomes idle (waiting for something)
- When workflow completes or terminates
- When transaction completes
- When CompensatableSequence completes
- When explicitly unloaded or when an activity marked with PersistOnClose ends.
In this post I cannot go into the details of writing your own workflow persistence service but it is not as dificult as you might think, though there are some details of the persistence mechanism. For all practical purposes the SQL service should enable you to create persistable workflows. In the next post we will look at workflow tracking, keep reading!