MsmqActivities v1.1 Released

Link. October 20, 2006. Comments [5]. Posted in: .NET | WinFX | Workflow

I’ve just uploaded a new release (v1.1) of my MSMQ Activities for Windows Workflow Foundation. This release does a few general fixes and polishes a few things here and there, but the largest change is a modification of the MsmqListenerService runtime service used by the MsmqReceiveActivity to listen to the MSMQ queues. This change is aimed at improving the situation I talked about on this past entry. Basically, this is something that will be very handy to ensure the activities work even when the hosting process dies unexpectedly and is restarted.

As part of this release, a new interface is introduced in the component: IMsmqSubscriptionPersistenceService (sorry for the long name). This interface is used by the MsmqListenerService to handle persistence of all subscriptions created at runtime to a given MSMQ Queue. This interface has three methods that are consumed by the listener service:

  • Persist(string host, MsmqSubscription subscription):
    This method should take the specified subscription and save it to a persistent storage, and is called when an MsmqReceiveActivity subscribes to a given MSMQ Queue.
    This method is called inside a System.Transactions.TransactionScope so that the listener service can abort the persistence if anything happens after that.
  • IEnumerable<MsmqSubscription> LoadAll(string host):
    This method is called when the listener service is started (right after the WorkflowEngine is started on the process, in fact) to get a list of all subscriptions stored for the given host. For each subscription that is loaded, the listener service configures again a listener on the queue the subscription relates to.
  • Remove(MsmqSubscription subscription):
    This method is called when a MsmqReceiveActivity removes a subscription to a queue. It should delete any record kept about the specified subscription in the persistent storage.

The host argument to Persist() and LoadAll() is a very basic mechanism to allow you to keep a single persistent storage for subscriptions coming from multiple applications (i.e. multiple processes/machines hosting the WorkflowRuntime). The host name to use is specified when you create the MsmqListenerService instance either through an argument in a new constructor overload, or through the configuration file through the “hostname” attribute. If you do not specify a hostname, the value “default” will be used instead. Be careful to always set the hostname explicitly if you’re going to be sharing the persistence storage.

Out of the box, I provide two implementations of the IMsmqSubscriptionPersistenceService interface:

  • NullMsmqSusbcriptionPersistenceService: This is an empty implementation that doesn’t do anything. It can be used if you simply don’t want or need to support subscription persistence.
  • SqlMsmqSubscriptionPersistenceService: This implementation stores all subscriptions as records in a table in a SQL Server database called “MsmqSubscriptions”.

You can select which implementation to use by simply adding it to the WorkflowRuntime’s runtime services collection (either through code or through the configuration file). In the case of the SQL implementation, you’ll need to provide the connection string to the database to use either through the constructor or through the “ConnectionString” attribute in the configuration XML.

Notice that you because of this, you could easily plug in your own custom persistence implementation to support other databases or repositories. One cool thing is that the WorkflowRuntime in essence acts here as an Inversion of Control (IoC) implementation for anything running on the Windows Workflow Foundation platform!



Friday, October 20, 2006 10:33:22 PM (SA Pacific Standard Time, UTC-05:00)
Hey Tomas - sorry I missed your earlier entry - but why not just have your service hook into the WorkflowLoaded event? That way if a Workflow came up from the persistence store and you didn't have a listener - you could recreate it from the Workflow definition (e.WorkflowInstance.GetWorkflowDefinition()).
Friday, October 20, 2006 10:44:03 PM (SA Pacific Standard Time, UTC-05:00)
Jon,

I thought about doing something similar, but I was under the impression that wouldn't quite work. Here's what I was thinking:
If the workflow is "stuck" waiting for the MSMQ message to arrive at the queue, and the host is unloaded, then when the host was reloaded the workflow instance wouldn't have been reloaded by the engine because it was idled and not running (at least that's what I understood from our earlier discussion in the forums). If so, hooking into the WorkflowLoaded event wouldn't do me any good as it is precisely my MsmqListenerService the one would be responsible for "waking" the workflow.

Besides of this, I don't see how hooking into the WorkflowLoaded event would've saved me the trouble of keeping track of the active subscriptions in a persistent store. Maybe I'm missing something, in which case I'd sure appreciate a hint :)
Saturday, October 21, 2006 12:00:20 AM (SA Pacific Standard Time, UTC-05:00)
I think you are correct that handling WorkflowLoaded won't work in this case -sorry I wasn't thinking it throught.

I am still concerned about your approach (essentially another persistence service to take care of). Especially in light of:

a) How will this work in a mulit-host instance environment
b) How will it stay consistent with the state of the workflow itself (what if your service gets out of sync with the current state of the workflow).

Which is why I would prefer some system that used the metadata of the activity instance itself - I would lean toward SqlPersistenceService.GetAllWorkflows - which would allow you to get the activity metadata without having to load it into memory. OTOH - this is only on the OOB persistence service.
Thursday, March 15, 2007 6:36:04 AM (SA Pacific Standard Time, UTC-05:00)
bug (SqlMsmqSubscriptionPersistenceService.cs):

public SqlMsmqSubscriptionPersistenceService(string connString)
{
if ( String.IsNullOrEmpty(_connectionString) )
throw new ArgumentNullException("connString");
_connectionString = connString;
}
Dub
Thursday, March 15, 2007 6:25:03 PM (SA Pacific Standard Time, UTC-05:00)
Dub,

Absolutely right. I've fixed it and updated the download. Thanks!
Comments are closed.

Syndicate

About

Tomas Restrepo is a software developer located in Colombia, South America. His interests include .NET, Connected Systems, PowerShell and lately dynamic programming languages. More...

tomasrestrepo @ twitter My Flickr photostream My saved links on delicious My Technorati Profile

email: tomas@winterdom.com
msn: tomasr@passport.com

View my profile on LinkedIn

MVP logo

Ads


Categories

Statistics

Total Posts: 1035
This Year: 105
This Month: 4
This Week: 2
Comments: 802

Archive

Other

Copyright © 2002-2008, Tomas Restrepo.

Powered by: newtelligence dasBlog 2.1.8139.823

Sign In