Sunday, October 15, 2006 3:15 AM bart

WF - Working with Tracking Services

Introduction

In the previous post I've covered the use of persistence services with Windows Workflow Foundation to enable long-running workflows in a reliable way. However, there's still another dark side to long-running workflows that needs a solution: what's happening inside? As you can imagine, a workflow in progress can be blocked waiting for a lot of things, such as the expiration of a timer to indicate a timeout (e.g. by putting a DelayActivity in parallel with another activity using a ParallelActivity) or a wait for an external chunk of data to arrive. In order to visualize what's going on inside, at runtime, the WF Gods created tracking services.

Getting started

Just like persistence services, tracking services rely on some store to put information - in casu tracking information - in. Again, WF comes with a SQL Server enabled service out of the box, called the SqlTrackingService. There's quite a bit to tell about tracking services, but we'll stick with the basics in this post. Nevertheless, a short list of cool things:

  • Filtering tracking information using tracking profiles
  • Querying tracked information using SqlTrackingQuery

These might get covered in much more detail somewhere in the future. As usual, in case you have questions, you can contact me too.

Right, on the the real stuff now. To enable tracking services using SQL Server (2000, 2005, MSDE, Express) we need to create a tracking database first. We'll use SQL Server 2005 Express Edition in this post (download here) with SQL Server Management Studio Express installed on the machine:

  1. Connect to the database server:


  2. Create a new database called SqlTrackingDemo:


  3. Now define the database structure and logic required by tracking services, based on two .sql scripts that ship with WF in the %windir%\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\EN folder:


  4. Execute (in order) Tracking_Schema.sql and Tracking_Logic.sql, while making sure you've selected the newly created database from step 2:


  5. Finally you should find a bunch of tables and stored procedures in the database (check this).

A tracking-enabled workflow project

A simple solution

Create a new Sequential Workflow Console Application first, called TrackingDemo:

Remove Workflow1 from the Solution Explorer and add a new Sequential Workflow Library project to the solution, called TrackingDemoLibrary:

This step is required because we'll use our workflow definition to visualize tracking information and to do so, the assembly containing the workflow definition will be put in the GAC (as shown later on). Next, add a reference to the TrackingDemoLibrary project in the TrackingDemo (host) project:

In the code of the host application (Program.cs) change the call to CreateWorkflow as follows:

WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(TrackingDemoLibrary.Workflow1));

Finally, go the project properties of TrackingDemoLibrary and make the assembly strong-named:

Defining the workflow

Now go to Workflow1 in the TrackingDemoLibrary project. First, parameterize the workflow by adding two properties to the code:

private string firstName;

public string
FirstName
{
   get { return
firstName; }
   set { firstName = value
; }
}

private int
age;

public int
Age
{
   get { return
age; }
   set { age = value
; }
}

Now create the following workflow definition:

In here, the IfElseActivity's plusEighteen branch relies on a Declarative Rule Condition defined as follows:

The ExecuteCode event handlers for the different CodeActivity activities are defined like this:

private void welcome_ExecuteCode(object sender, EventArgs e)
{
   Console.WriteLine("Welcome "
+ firstName);
}

private void allowAccess_ExecuteCode(object sender, EventArgs
e)
{
   Console.ForegroundColor = ConsoleColor
.Green;
   Console.WriteLine("You're granted access"
);
   Console
.ResetColor();
}

private void denyAccess_ExecuteCode(object sender, EventArgs
e)
{
   Console.ForegroundColor = ConsoleColor
.Red;
   Console.WriteLine("You're denied access"
);
   Console
.ResetColor();
}

Finally, the delay activities in the workflow were added to simulate long-running operations and have a timeout value set to 10 seconds.

To test things, go to the Program.cs file and change the workflow instance creation code to pass through parameters:

Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add(
"FirstName", "Bart"
);
parameters.Add(
"Age"
, 23);

WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(TrackingDemoLibrary.Workflow1
), parameters);
instance.Start();

No magic yet:

Track it

Time to enable tracking. This is done by adding just one single line of code to the host code (Program.cs):

using System.Workflow.Runtime.Tracking;

...

workflowRuntime.AddService(new SqlTrackingService("Data Source=localhost\\SQLEXPRESS;Initial Catalog=SqlTrackingDemo;Integrated Security=SSPI;"));

Now, execute the application once more and then go to the SQL Server Management Studio Express to execute the following query:

use SqlTrackingDemo
exec dbo.GetWorkflows

This will result in something like this (a few columns were hidden in the screenshot):

In here you can see the identifier of the workflow instance as well as information about the workflow type. Other database tables include much more detailed information about the current state the workflow is in, effectively enabling tracking scenarios. Instead of doing low level work with these tables or stored procedures, we'll use a monitor application to see what's going on.

Lights on the WorkflowMonitor

When you install the Windows SDK, a folder with samples is created on the system, typically in %programfiles%\Microsoft SDKs\Windows\v6.0\Samples:

Extract the WFSamples.zip folder to some location on your system. In the Applications\WorkflowMonitor\CS subfolder of the samples, you'll find a WorkflowMonitor application that we'll take a look at now. Open it in Visual Studio 2005.

Now run the application. After a few seconds, the app will crash with the following error message:

This is because we didn't use the default configuration for tracking (i.e. different database name etc). However, we get the opportunity to change the settings right away:

The settings shown above are the valid ones in our case, using SQL Server 2005 Express with the right database name and a polling time of 5 seconds.

When you now try to start the monitoring (using the green "play" button) you'll likely see the following error (or something similar). You might need to restart the application to see the message popping up too:

Basically this means that the WorkflowMonitor is able to get the workflows using GetWorkflows but now tries to load the type specified in the database to visualize the workflows (which may be in flight). For the WorkflowMonitor to find our TrackingDemoLibrary.Workflow1 type, it will need to find the assembly containing the definition. You can either copy the dll file to the bin\Debug (or bin\Release depending on how you're running the WorkflowMonitor sample) folder of the WorkflowMonitor or register the workflow definition in the GAC. We choose the latter one:

Now restart the WorkflowMonitor and you should see something like this:

Notice the mark signs indicate the followed path during execution. It's a very interesting time investment to look at the code of this sample to find out how the workflow information is queried using SqlTrackingQuery. This sample is also interesting because of the designer rehosting used to visualize the workflow in the right-hand side pane. I'll cover designer rehosting some time in the future on this blog too.

Now, run our workflow application again while the monitor is polling the tracking database. Contrary to what you might expect, you won't see a new workflow instance appearing in the list right away. This happens because tracking only performs its job when asked so, e.g. because of a persistence opportunity (this statement is somewhat simplified, check out the docs to get full info on how the system works, related to work batches and so on). As an exercise, try to combine persistence (see previous post) with tracking to track a workflow in progress. You'll end up with a piece of hosting code like this:

workflowRuntime.AddService(
   new SqlWorkflowPersistenceService(
      "Data Source=localhost\\SQLEXPRESS;Initial Catalog=SqlPersistenceDemo;Integrated Security=SSPI;"
,
      true
,
      TimeSpan
.FromHours(1.0),
      TimeSpan
.FromSeconds(5.0)
   )
);

workflowRuntime.AddService(
   new SqlTrackingService
(
      "Data Source=localhost\\SQLEXPRESS;Initial Catalog=SqlTrackingDemo;Integrated Security=SSPI;"
   )
);

Chances are high your app will block or throw an exception. This is because the system needs to connect to the two databases at the same time in a transactional manner. To have this work, you need to start the DTC service on your machine:

Now execute the app again and you should see the following in the monitor:

As you can see, it's now possible to monitor a workflow in flight.

Note: An alternative approach to avoid the DTC problem is to use the - fasten your seatbelts - SharedConnectionWorkflowCommitBatchService service instead of a combination of the tracking service and the persistence service. As the name implies, this one uses a shared connection for both, effectively avoiding distributed transactions and the need for DTC to be enabled and started on the machine. I won't cover this here.

Conclusion

The use of long-running workflows in combination with a lot of services can turn the whole thing in a opaque box without you (and managers) knowing what's going on inside. Tracking services are the window into the internals of workflow instances in all their states, even when in progress. Combining this goodness with things like designer rehosting can open up a lot of great scenarios as shown in the WorkflowMonitor sample.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under: ,

Comments

# re: WF - Working with Tracking Services

Sunday, October 15, 2006 2:45 PM by Stefano Demiliani

This series of posts regarding WF is really wonderful. Don't stop posting interesting things like that Bart.

# re: WF - Working with Tracking Services

Sunday, October 15, 2006 9:06 PM by bart

Stefano,

Thanks for reading my posts. I'd say: don't worry be happy, the next four days WF posts will appear online.

-Bart

# Windows Workflow Foundation Resources

Tuesday, October 17, 2006 7:04 PM by while(availableTime>0) {

Since I&#180;ve been working with Windows Workflow Foundation (Project BHAL), I&#180;ve gathered quite a list of...

# The Roadshow has Begun!

Saturday, March 03, 2007 8:39 AM by Chris Bowen's Blog

We'd like to extend a big thank you to everyone who attended the first two stops of Bob &amp; Chris'

# The Roadshow Has Begun!

Saturday, March 03, 2007 8:43 AM by RSS It All

We&#39;d like to extend a big thank you to everyone who attended the first two stops of Bob &amp; Chris&#39;