C# WF4:工作流保持锁定

C# WF4:工作流保持锁定,c#,.net,c#-4.0,workflow-foundation-4,C#,.net,C# 4.0,Workflow Foundation 4,我有一个使用WorkflowApplication在IIS中承载WF4工作流的应用程序 工作流由用户定义(使用重新宿主的工作流设计器),xml存储在数据库中。然后,根据使用应用程序的用户操作,在数据库中选择一个xml,并创建/恢复工作流 我的问题是:当工作流到达书签并处于空闲状态时,它会在不同的时间内保持锁定。然后,如果用户尝试对此工作流执行其他操作,我会遇到以下异常: InstancePersistenceCommand的执行被中断,因为实例“52da4562-896e-4959-ae40-5

我有一个使用WorkflowApplication在IIS中承载WF4工作流的应用程序

工作流由用户定义(使用重新宿主的工作流设计器),xml存储在数据库中。然后,根据使用应用程序的用户操作,在数据库中选择一个xml,并创建/恢复工作流

我的问题是:当工作流到达书签并处于空闲状态时,它会在不同的时间内保持锁定。然后,如果用户尝试对此工作流执行其他操作,我会遇到以下异常:

InstancePersistenceCommand的执行被中断,因为实例“52da4562-896e-4959-ae40-5cd016c4ae79”被其他实例所有者锁定。发生此错误的原因通常是加载了实例的主机不同。实例上带有锁的所有者或主机的实例所有者ID为“d7339374-2285-45b9-b4ea-97b18c968c19”

现在是编写代码的时候了

当我的工作流处于空闲状态时,我指定应卸载它:

private PersistableIdleAction handlePersistableIdle(WorkflowApplicationIdleEventArgs arg)
{
    this.Logger.DebugFormat("Workflow '{1}' is persistableIdle on review '{0}'", arg.GetReviewId(), arg.InstanceId);
    return PersistableIdleAction.Unload; 
}
对于我需要的每个WorkflowApplication,我创建一个新的SqlWorkflowInstanceStore:

var store = new SqlWorkflowInstanceStore(this._connectionString);
store.RunnableInstancesDetectionPeriod = TimeSpan.FromSeconds(5);
store.InstanceLockedExceptionAction = InstanceLockedExceptionAction.BasicRetry;
下面是如何创建WorkflowApplication的

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;
然后我调用Run方法来启动它。 一些解释:
-root.RootActivity:它是根据存储在数据库中的工作流XML创建的活动
-CustomSynchronizationContext:处理授权的同步上下文
-在handleUnloaded方法中,我记录了工作流卸载的时间,并且我看到在下一个用户操作之前工作流已正确卸载,但在卸载之后工作流似乎保持锁定(?)

然后,稍后,当我需要恢复工作流时,我会以与调用相同的方式创建工作流:

wfApp.Load(workflowInstanceId);
引发上面指定的“锁定”异常。 如果我等几分钟,然后再试一次,它工作正常

我看到一篇帖子说我们需要设置一个所有者。 因此,我还尝试使用静态SqlWorkflowInstanceStore,其所有者设置使用以下代码:

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;
但我有一个例外:

InstancePersistenceCommand的执行被中断,因为 所有者ID的实例所有者注册 “9efb4434-8560-469f-9d03-098a2d48821e”已无效。这个错误 指示所有实例的内存中副本已被此锁定 所有者已过时,应将其与 实例句柄。通常,最好通过重新启动来处理此错误 主持人

是否有人知道如何确保在卸载工作流时立即释放工作流上的锁? 我见过一些人使用WorkflowServiceHost(使用WorkflowIdleBehavior)来实现这一点,但这里我没有使用WorkflowServiceHost,而是使用WorkflowApplication


谢谢你的帮助

我怀疑问题出在SqlWorkflowInstanceStore的InstanceOwner上。它不会被删除,因此工作流需要等待上一个的所有权超时

创建实例所有者

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;
var deleteOwnerCmd = new DeleteWorkflowOwnerCommand();
instanceStore.Execute(instanceHandle, deleteOwnerCmd, TimeSpan.FromSeconds(30));
删除实例所有者

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;
var deleteOwnerCmd = new DeleteWorkflowOwnerCommand();
instanceStore.Execute(instanceHandle, deleteOwnerCmd, TimeSpan.FromSeconds(30));

另一个可能的问题是,当工作流中止时,未调用卸载的回调。

是否需要对所有WorkflowApplication使用1个store/1 owner,或对WorkflowApplication使用1个store/owner?因为我已经为所有WfApp尝试了一个静态存储,没有删除所有者,我收到了第二条错误消息。所有这些都在webservice应用程序(托管在IIS中)中使用。第二个错误似乎是所有权很短的结果。我会为每个WorkflowApplication使用一个带有InstanceOwner的SqlWorkflowInstanceStore。为每个WorkflowApplication创建/删除所有者可以正常工作。但是当我这样做的时候,我发现了一个错误,在某些情况下,wf被加载了,但是由于条件的原因,没有调用ResumeBookmark,所以wf永远保持加载状态(并且永远锁定?)。现在在这种情况下,我调用Unload。乍一看这里已经没有锁了。是的,这是值得一试的。如果加载工作流但工作流未运行,则意味着ot不会空闲,因此也不会卸载。创建实例存储时,每个进程不需要超过一个实例存储。查看此链接以了解最佳实践