Listing and resuming workflow instances

We recently had a need to list suspended Workflow Foundation 4 instances hosted in Windows Server AppFabric from code, and here’s how to do it:

SqlInstanceQueryProvider provider = new SqlInstanceQueryProvider();
var providerArgs = new NameValueCollection { { "connectionString", _instanceStoreConnectionString } };
provider.Initialize("WfInstanceProviderA", providerArgs);

InstanceQuery query = provider.CreateInstanceQuery();
var args = new InstanceQueryExecuteArgs { InstanceStatus = InstanceStatus.Suspended };

IAsyncResult asyncResult = query.BeginExecuteQuery(args, new TimeSpan(0, 0, 0, 30), null, null);
IEnumerable instances = query.EndExecuteQuery(asyncResult);

By the way, this requires a reference to Microsoft.ApplicationServer.StoreManagement.dll which is installed with AppFabric.

Resuming the workflow instances can be done like this:

SqlInstanceControlProvider provider = new SqlInstanceControlProvider();
var providerArgs = new NameValueCollection { { "connectionString", _instanceStoreConnectionString } };
provider.Initialize("WfInstanceProviderA", providerArgs);

InstanceControl control = provider.CreateInstanceControl();

foreach (InstanceInfo instanceInfo in instances)
{
    InstanceCommand cmd = new InstanceCommand
    {
        CommandType = CommandType.Resume,
        InstanceId = instanceInfo.InstanceId,
        ServiceIdentifier = instanceInfo.HostInfo.HostMetadata
    };

    // Not included in instanceInfo.HostInfo.HostMetadata...
    cmd.ServiceIdentifier["VirtualPath"] = 
         "/EducationWorkflowServices/AktivitetService.xamlx";

    IAsyncResult asyncResult = control.CommandSend.BeginSend(cmd,
        new TimeSpan(0, 0, 0, 30), null, null);
    control.CommandSend.EndSend(asyncResult);
}

AppFabric also has some great PowerShell cmdlets for administration that can be used for the same thing. Here are a few examples:

Import-Module ApplicationServer
Get-ASAppServiceInstance -status 'suspended'
Get-ASAppServiceInstance -status 'suspended' | Resume-ASAppServiceInstance
Get-ASAppServiceInstance -status 'suspended' | Stop-ASAppServiceInstance -Terminate
Get-ASAppServiceInstance -status 'suspended' | Remove-ASAppServiceInstance
Get-ASAppServiceInstance -InstanceId 95a25419-0d71-42c4-ab70-aa523ba603fc
Get-ASAppServiceInstance -InstanceId 95a25419-0d71-42c4-ab70-aa523ba603fc | Suspend-ASAppServiceInstance

Yet another alternative is to query the AppFabric persistance store database directly using SQL:

SELECT *
FROM [AppFabric_Application_Extensions].[System.Activities.DurableInstancing].[InstancesTable]
WHERE IsSuspended=1

Choose the alternative most to your liking 🙂

/Emil

The case of the slow for-loop

We recently had a problem with a page in an MVC application that was very slow, it took minutes before the server finished creating it. It turned out that it was this for-loop that caused the problem:

for (int i = 0; i < Model.Deltagare.Count(); i++)
{
  var deltagare = Model.Deltagare.ElementAt(i);
  ...
}

where Model.Deltagare is an IEnumerable. This is a common construct when you need to track the loop index for some reason but it turns out that its use really should be discouraged. The problem is that ElementAt(i) can take a really long time depending on the underlying list type of the enumerable. If it’s an array, it’s really quick, but in our case it was a System.Linq.Enumerable.WhereSelectListIterator and apparently ElementAt(i) had to traverse the enumerator from the start each time it was called. That’s not what you want to use an iterator for…

We changed the above loop to a foreach-loop instead, so that the iterator can be used more naturally:

int i;
foreach (var deltagare in Model.Deltagare)
{
  ...
  i++;
}

The duration of our loop went from about 10 minutes to 1 second for a list of about 6000 items.

Lesson learned.

/Emil