我有一个使用 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);
抛出上面指定的“锁定”异常。如果我等待几分钟,然后再试一次,它工作正常。
我在这里读到一篇文章说我们需要设置一个所有者。因此,我还尝试使用以下代码将静态 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 一起丢弃。通常,最好通过重新启动主机来处理此错误。
有谁知道如何确保在卸载工作流时立即释放工作流上的锁定?我看到一些帖子使用 WorkflowServiceHost(使用 WorkflowIdleBehavior)执行此操作,但这里我没有使用 WorkflowServiceHost,我使用的是 WorkflowApplication
感谢您的任何帮助!