Sunday, December 27, 2009

Windows WF Persistence

Introduction:

Workflows consist of various activities. Some of these activities might be blocking which requires waiting for something to happen as part of the workflow process within or outside it. This generally happens when workflows involved human interactions. Windows WF provides this amazing facility of persistence of workflows for these blocking activities.


Benefits of Persistence:

The greatest thing is that it can not only survive a host application environment crash but it could also survive a host machine crash due to persistence. If a host system is crashed workflow should be able to restore to another machine without any issue. Let’s see!


There are many processes running on our machines at the same time. Pushing our workflows to the persistent storage would free up some memory resources to be available to for other processes increasing the overall performance of your systems.


Put it to test! But what test is it exactly?

Workflows can be long running. There might be scenarios in which workflows are waiting of some action to proceed further. This might be any external calls or internal event or anything else. A good workflow engine should support us in these long running scenarios. If Windows WF passes this criterion then we might call it to be a good workflow environment. It supports these scenarios using off-the-shelf Persistence Service provided. Remember that we can always override the default implementation of these services with our custom implementations.


Default WF Persistence Service:

The default persistence service provided with Windows WF is SqlWorkflowPersistenceService. This service keeps the workflow object in SQL Server database for persistence.


The database will obviously have to have a schema that the persistence service knows about. To create this database, you can use some SQL scripts that come with WF. These scripts are placed in the C:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL folder after installing WF on your machine. There are separate SQL scripts for creating the schema and the stored procedures (logic) that need to go into that database.


When to Persist?

  1. Waiting for some Requests:

We might want to free some resources when we are waiting for something to happen and workflow is idle. This can be provided declaratively or through code.


  1. On demand persistence:

In this scenario, workflow is not waiting for some trigger but we just want to load workflow to persistence. This type of unloading generally takes place through code. This might be because of releasing some resource. Specially, on demand rehydration might help in case of failure recovery.


Terminologies:

Let us discuss the terminologies used in workflow world related to persistence. We might call them workflow persistence slangsJ. In order to communicate with workflow community, we must know them.


Dehydration:

To move workflows to persistence store is called dehydration. As discussed, the default persistence service with WF provides dehydration of workflows in SQL Server database. This is also called “Unloading”.

Re-Hydration:

Hydration is about loading the workflow objects from persistence store back to the workflow runtime. This is also called “Loading”.


Enough Study, Let’s Practice!

You would be amazed to know that using WF Persistence Service is just about executing two scripts (To create database schema. They are already provided by Microsoft) and adding a configuration in app.config file. For supporting developers even more, some events are provided which can be used for housekeeping work for the workflow.


Step # 01 (Create Database)

Let us create a database named WorkflowPersistenceServicePractice.

CREATE DATABASE WorkflowPersistenceServicePractice


Step # 02 (Execute SqlPersistenceService_Schema.sql script)

As discussed above that this script should be available as part of .net 3.0 installation. Find the script in the path specified above and execute it in the database created in Step 1.


This script takes care of creating a role named state_persistence_users to the database. Additionally, it creates two tables and creates indexes on them. The tables’ names are as follows:

  1. InstanceState:

This is to hold the details about the workflow instances currently in persistence store. As soon as a workflow object is rehydrated, the information about workflow instance is removed from this table.


  1. CompletedScope: This is used for workflows that use compensation.

The workflow state is stored in database as image data. Image is a SQL Server datatype which can hold up to 2,147,483,647 bytes.


Step #03 (Execute SqlPersistenceService_Logic.sql script)

This script is also installed with Windows WF installation. Executing this script would create some stored procedures. These stored procedures are used by WF for DML operations involving the persistence of workflow object by WF runtime.


The list of stored procedures created, is as follows:

1. InsertInstanceState

2. RetrieveAllInstanceDescriptions

3. UnlockInstanceState

4. RetrieveInstanceState

5. RetrieveNonblockingInstanceStateIds

6. RetrieveANonblockingInstanceStateId

7. RetrieveExpiredTimerIds

8. InsertCompletedScope

9. DeleteCompletedScope

10. RetrieveCompletedScope


Step # 04: (Adding Service to Runtime)


Declarative Option:

Some configurations are required to provide WF about the details of persistence service to use.

Add reference of System.configuration.dll library and update Services section of app.config file by adding the details of the persistence service to use:


<xml version="1.0" encoding="utf-8" ?>

<configuration>

<configSections>

<section name="HostingWorkflowRuntime" type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

configSections>

<HostingWorkflowRuntime Name="Hosting">

<CommonParameters/>

<Services>

<add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime,Version=3.0.00000.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35"

connectionString="Initial Catalog=WorkflowPersistenceServicePractice;Data Source=localhost;Integrated Security=SSPI;"

LoadIntervalSeconds="5" />

</Services>

</HostingWorkflowRuntime>

</configuration>


While creating the workflow runtime object in the hosting application, we have to specify the runtime configuration section to use in our app.config file. You can see that we have provided configuration for persistence service in HostingWorkflowRuntime section of our configuration.


WorkflowRuntime workflowRuntime = new WorkflowRuntime("HostingWorkflowRuntime")


Addition of Service through Code:

In the following code, we are adding a persistence service which unloads the workflow instance when idle to the database as specified by the assigned connection string. This seems more practical because in many cases, workflows might be developed by some other team and you might not want to use the configuration settings in the workflow library created by the workflow team.


Dim myConnectionString = ""//assign connection string to persistence DB


NameValueCollection args = new NameValueCollection();

args.Add("ConnectionString", myConnectionString);

args.Add("UnloadOnIdle", "true");


SqlWorkflowPersistenceService persistenceService = new SqlWorkflowPersistenceService(args);

runtime.AddService(persistenceService);


Step #05 (Housekeeping Operations in Events)

WorkflowRuntime provides various events for providing developers mechanism to write application specific logic before or after hydration / dehydration of workflow objects. Most of them are not persistence specific but they are generally used with persistence. The following is the details of such events:

  1. WorkflowPersisted
  2. WorkflowLoaded
  3. WorkflowUnLoaded
  4. WorkflowIdled

No comments: