Wednesday, 25 January 2012

Tracking self hosted WorkflowApplication events

There are a numerous examples out there showing how to configure workflow instance tracking most if not all assume that the workflows are hosted in and exposed via WorkflowServiceHost. Tracking profiles can be configured using xml in the configuration file when using this mechanism for hosting your workflow service.
<system.serviceModel>
    <tracking>  
      <trackingProfile name="Sample Tracking Profile">
        <workflow activityDefinitionId="*">
          <workflowInstanceQueries>
            <workflowInstanceQuery>
              <states>
                <state name="Started"/>
                <state name="Completed"/>
              </states>
            </workflowInstanceQuery>
          </workflowInstanceQueries>
        </workflow>
      </trackingProfile>        
    </profiles>
  </tracking>
</system.serviceModel>

So what if you are not hosting in a WorkflowServiceHost but hosting WorkflowApplication objects in your own host process what are the options.

The first option is to define the tracking profile in the application configuration file and then load the tracking profile using code similar to the GetProfile method here. One of the problems with this approach in my mind stems from the fact that the XML definition is defined below the system.serviceModel so you are required to define a system.serviceModel element in your application configuration file regardless of whether or not you are using WCF. This in my mind was not the best approach to take for configuration of tracking profiles. An alternate would have been to create a separate element that the system.service model configuration could reference maybe by name.

The second option is to specify the tracking profile configuration in code and apply the tracking profile to a tracking participant more on this later in this post. First lets take a look at tracking profiles.

Tracking Profiles

A tracking profile determines which tracking records get processed by a tracking participant. There numerous tracking records that are generated by a given workflow instance during its execution. WF4 tracking has a number of TrackingQuery derived classes that are used to create subscriptions to WF4 workflow tracking records. The following is a list of the tracking query types and there purpose:

  • WorkflowInstanceQueryUsed to track workflow instance related events. For example Started,Completed,Aborted events.
  • CustomTrackingQueryUse this to create your own custom tracking query in combination with custom tracking records.
  • ActivityScheduledQueryUsed to track various events related to activities. Includes events to indicate that a particular activity was scheduled, started or completed.
  • FaultPropagationQueryYou can this query to detect errors that are raised within activities in the workflow.
  • CancelRequestedQueryEvery time the workflow tries to cancel one of its children a CancelRequestedRecord is written.
  • BookmarkResumptionQueryUsed to track bookmark resumption events.

Tracing WorkflowApplication

For the application that I am delivering I do not need the flexibility defining TrackingQuery types in a configuration file. I want to log all events and apply filtering when viewing the events. The following is an example method to apply the tracking profile to a tracking participant:


private static void ConfigureTrackingParticipent(TrackingParticipant trackingParticipant, WorkflowApplication workflowApplication)
{
    var trackingProfile = new TrackingProfile()
    {
        ActivityDefinitionId = "*",
        ImplementationVisibility = ImplementationVisibility.All,
        Name = "TrackingProfile"
    };
    var workflowInstanceQuery = new WorkflowInstanceQuery();
    workflowInstanceQuery.States.Add("*");
    var activityScheduledQuery = new ActivityScheduledQuery();     activityScheduledQuery.ActivityName = "*";     activityScheduledQuery.ChildActivityName = "*";
    var faultPropagationQuery = new FaultPropagationQuery();     faultPropagationQuery.FaultHandlerActivityName = "*";     faultPropagationQuery.FaultSourceActivityName = "*";
    var cancelRequestedQuery = new CancelRequestedQuery();     cancelRequestedQuery.ActivityName = "*";     cancelRequestedQuery.ChildActivityName = "*";
    var bookmarkResumptionQuery = new BookmarkResumptionQuery();     bookmarkResumptionQuery.Name = "*";
    trackingProfile.Queries.Add(workflowInstanceQuery);     trackingParticipant.TrackingProfile = trackingProfile;     workflowApplication.Extensions.Add(trackingParticipant); }

Note the “*” is a wild card which allow you to subscribe to all of the relevant tracking records for a given tracking query type. For example activityScheduledQuery.ActivityName = "*"; subscribes to all activities. Which is exactly what I want as workflows are dynamically loaded into my hosting process so I do not know up front what activities are defined in the workflow.

The tracking participant is then conditionally applied to a given WorkflowApplication, in my case I am using a EtwTrackingParticipant participant but this could be a custom tracking participant.

if (WorkflowManagerSettings.Current.EnableETWTracing)
{
    var etwTrackingParticipant = new EtwTrackingParticipant();
    etwTrackingParticipant.ApplicationReference = "WorkflowEngine";
    ConfigureTrackingParticipent(etwTrackingParticipant, workflowApplication);
}


The output from the tracking can be viewed  with the system event viewer. Expand the Applications and Services Logs node then expand the Microsoft, Windows, and Application Server-Applications nodes

Capture

No comments:

Post a Comment