WF4:工作流程保持锁定状态

时间:2012-10-09 10:25:40

标签: c# .net c#-4.0 workflow-foundation-4

我使用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; 
}

我需要的Foreach 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);

抛出"锁定"上面指出的例外。 如果我等了几分钟,再试一次,它就可以了。

我看了一篇帖子here,说我们需要设置一个所有者。 所以我也尝试使用静态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'已变得无效。这个错误   表示由此锁定的所有实例的内存中副本   老板已经变得陈旧,应该随便丢弃   InstanceHandles。通常,最好通过重新启动来处理此错误   主持人。

有人知道如何确保在卸载工作流时立即释放工作流上的锁定吗? 我已经看到一些post使用WorkflowServiceHost(使用WorkflowIdleBehavior)执行此操作,但此处我使用WorkflowServiceHost,我使用WorkflowApplication

感谢您的帮助!

1 个答案:

答案 0 :(得分:3)

我怀疑问题出在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));

另一个可能的问题是,当工作流中止时,不会调用Unloaded回调。