WF4: Workflow stay locked

I've an application that host WF4 workflow in IIS using WorkflowApplication

The workflow is defined by user (using a rehosted workflow designer) and the xml is stored in the database. Then, depending on user actions using the application, an xml is selected in database and the workflow are created / resumed.

My problem is: when the workflow reach a bookmarks and go idle, it stay locked for a various amount of time. Then, if the user try to make another action concerning this workflow, I got this exception:

The execution of an InstancePersistenceCommand was interrupted because the instance '52da4562-896e-4959-ae40-5cd016c4ae79' is locked by a different instance owner. This error usually occurs because a different host has the instance loaded. The instance owner ID of the owner or host with a lock on the instance is 'd7339374-2285-45b9-b4ea-97b18c968c19'.

Now it's time for some piece of code

When I workflow goes idle, I specify it should be unloaded:

private PersistableIdleAction handlePersistableIdle(WorkflowApplicationIdleEventArgs arg)
{
    this.Logger.DebugFormat("Workflow '{1}' is persistableIdle on review '{0}'", arg.GetReviewId(), arg.InstanceId);
    return PersistableIdleAction.Unload; 
}

Foreach WorkflowApplication I need, I create a new SqlWorkflowInstanceStore:

var store = new SqlWorkflowInstanceStore(this._connectionString);
store.RunnableInstancesDetectionPeriod = TimeSpan.FromSeconds(5);
store.InstanceLockedExceptionAction = InstanceLockedExceptionAction.BasicRetry;

Here is how my WorkflowApplication is created

WorkflowApplication wfApp = new WorkflowApplication(root.RootActivity);
wfApp.Extensions.Add(...);
wfApp.InstanceStore = this.createStore();
wfApp.PersistableIdle = this.handlePersistableIdle;
wfApp.OnUnhandledException = this.handleException;
wfApp.Idle = this.handleIdle;
wfApp.Unloaded = this.handleUnloaded;
wfApp.Aborted = this.handleAborted;
wfApp.SynchronizationContext = new CustomSynchronizationContext();
return wfApp;

Then I call the Run method to start it. Some explanations:
- root.RootActivity: it's the activity created from the workflow XML stored in database
- CustomSynchronizationContext: a synchronisation context that handle authorisations
- in the handleUnloaded method I log when a workflow is unloaded, and I see that the workflow is correctly unloaded before the next user action, but it seems the workflow stay locked after being unloaded (?)

Then, later, when I need to resume the workflow, I create the workflow the same way then I call:

wfApp.Load(workflowInstanceId);

which throw the "locked" exception specified above. If I wait a few minutes, and try again, it works fine.

I read a post here that say we need to set an owner. So I've also tried using a static SqlWorkflowInstanceStore with the owner set using this code:

if (_sqlWorkflowInstanceStore != null)
    return _sqlWorkflowInstanceStore;

lock (_mutex)
{
    if (_sqlWorkflowInstanceStore != null)
        return _sqlWorkflowInstanceStore;

    // Configure store
    _sqlWorkflowInstanceStore = new SqlWorkflowInstanceStore(this._connectionString);
    _sqlWorkflowInstanceStore.RunnableInstancesDetectionPeriod = TimeSpan.FromSeconds(5);
    _sqlWorkflowInstanceStore.InstanceLockedExceptionAction = InstanceLockedExceptionAction.BasicRetry;

    // Set owner - Store will be read-only beyond this point and will not be configurable anymore
    var handle = _sqlWorkflowInstanceStore.CreateInstanceHandle();
    var view = _sqlWorkflowInstanceStore.Execute(handle, new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(5));
    handle.Free();

    _sqlWorkflowInstanceStore.DefaultInstanceOwner = view.InstanceOwner;
}

return _sqlWorkflowInstanceStore;

But then I've this kind of exception:

The execution of an InstancePersistenceCommand was interrupted because the instance owner registration for owner ID '9efb4434-8560-469f-9d03-098a2d48821e' has become invalid. This error indicates that the in-memory copy of all instances locked by this owner have become stale and should be discarded, along with the InstanceHandles. Typically, this error is best handled by restarting the host.

Does anyone know how to be sure that the lock on the workflow is released immediately when the workflow is unloaded ? I've see some post doing this with a WorkflowServiceHost (using WorkflowIdleBehavior) but here I'm not using WorkflowServiceHost, I'm using WorkflowApplication

Thank you for any help!


I suspect the problem is with the InstanceOwner of the SqlWorkflowInstanceStore. It isn't deleted so the workflow needs to wait for the ownership of the previous one to time out.

Creating an instance owner

var instanceStore = new SqlWorkflowInstanceStore(connStr);

var instanceHandle = instanceStore.CreateInstanceHandle();
var createOwnerCmd = new CreateWorkflowOwnerCommand();
var view = instanceStore.Execute(instanceHandle, createOwnerCmd, TimeSpan.FromSeconds(30));
instanceStore.DefaultInstanceOwner = view.InstanceOwner;

Deleting an instance owner

var deleteOwnerCmd = new DeleteWorkflowOwnerCommand();
instanceStore.Execute(instanceHandle, deleteOwnerCmd, TimeSpan.FromSeconds(30));

Another possible issue is that when a workflow aborts the Unloaded callback isn't called.

链接地址: http://www.djcxy.com/p/95892.html

上一篇: WF4 RC的“类型未定义”异常

下一篇: WF4:工作流保持锁定状态