gpt4 book ai didi

c# - 工作流基础 4.5 InstanceLockedException

转载 作者:太空宇宙 更新时间:2023-11-03 21:34:44 25 4
gpt4 key购买 nike

我目前正在 WCF 服务器架构的客户端中试验 Workflow Foundation 4.5。

我设置服务器的方式是创建一个常规的 WCF 服务应用程序(不是 WCF 工作流服务应用程序)并添加一堆 Web 方法来启动、恢复和获取工作流中实体的状态。

所以我有这样的东西:

public class WebService1 : WebService
{
private const string ConnectionString = "Server=.\\SQLEXPRESS;Initial Catalog=WF45GettingStartedTutorial;Integrated Security=SSPI";
private SqlWorkflowInstanceStore _store;

public SqlWorkflowInstanceStore Store
{
get
{
if (_store == null)
{
Debug.WriteLine("Building new store");
_store = new SqlWorkflowInstanceStore(ConnectionString);
StateMachineStateTracker.Promote(Store);
}

return _store;
}
}

[WebMethod]
public Guid Start(Guid resourceId)
{
var activity = new Activity1(); // My state machine
var parameters = new Dictionary<string, object> { { "resourceId", resourceId } };
var wfApp = new WorkflowApplication(activity, parameters, new WorkflowIdentity("v1", new Version(1, 0), string.Empty));
ConfigureWorkflowApplication(wfApp);
wfApp.Run();
return wfApp.Id;
}

[WebMethod]
public void Resume(Guid instanceId, string bookmarkName, object bookmarkParameter)
{
var activity = new Activity1();
var wfApp = new WorkflowApplication(activity, new WorkflowIdentity("v1", new Version(1, 0), string.Empty));
ConfigureWorkflowApplication(wfApp);
wfApp.Load(instanceId);
wfApp.ResumeBookmark(bookmarkName, bookmarkParameter);
}

[WebMethod]
public string GetCurrentState(Guid instanceId)
{
var activity = new Activity1();

// Things get messy here :

// var instance = WorkflowApplication.GetInstance(instanceId, Store);
// var wfApp = new WorkflowApplication(activity, instance.DefinitionIdentity);

// so replaced with :
var wfApp = new WorkflowApplication(activity, new WorkflowIdentity("v1", new Version(1, 0), string.Empty));

ConfigureWorkflowApplication(wfApp);
var trackerInstance = StateMachineStateTracker.LoadInstance(instanceId, wfApp.WorkflowDefinition, ConnectionString);
if (trackerInstance != null)
{
return trackerInstance.CurrentState;
}

return string.Empty;
}

private void ConfigureWorkflowApplication(WorkflowApplication wfApp)
{
// Configure the persistence store.
wfApp.InstanceStore = Store;

// State machine tracker taken from http://code.msdn.microsoft.com/windowsdesktop/Windows-Workflow-fee72008
var tracker = new StateMachineStateTracker(wfApp.WorkflowDefinition);
wfApp.Extensions.Add(tracker);
wfApp.Extensions.Add(new StateTrackerPersistenceProvider(tracker));

wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e)
{
Debug.WriteLine("Workflow completed.");
};

wfApp.Aborted = delegate(WorkflowApplicationAbortedEventArgs e)
{
Debug.WriteLine(string.Format("Workflow Aborted. Exception: {0}\r\n{1}",
e.Reason.GetType().FullName,
e.Reason.Message));
};

wfApp.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
{
Debug.WriteLine(string.Format("Unhandled Exception: {0}\r\n{1}",
e.UnhandledException.GetType().FullName,
e.UnhandledException.Message));
return UnhandledExceptionAction.Terminate;
};

wfApp.PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e)
{
return PersistableIdleAction.Unload;
};
}
}

现在,我想要的是从实例 ID 获取工作流版本,所以在我的 GetCurrentState 中调用:

var instance = WorkflowApplication.GetInstance(instanceId, Store);

然后加载 WorkflowApplication

var wfApp = new WorkflowApplication(activity, instance.DefinitionIdentity)

这工作正常,但我怀疑以某种方式让我的工作流主机加载,并且我的实例被锁定。

因此,当调用 GetCurrentState() 之后,客户端调用 Resume() 时,我得到以下异常(在 wfApp.Load(instanceId) 行)。

InstanceLockedException

The execution of an InstancePersistenceCommand was interrupted because the instance 'a1bcbd11-50fc-4a72-b5d2-87b71d0c3c45' 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 '190ea0d9-788f-4278-883e-84226f5788bc'.

当我停止使用 WorkflowApplication.GetInstance 方法并手动指定版本时,此异常消失,但我宁愿避免这种情况。

那么我在这里做错了什么?

谷歌搜索把我带到了这些页面:

InstanceLockedException: How to handle locking issues with WF 4.0?

-> 看起来像我遇到的问题,但我不确定如何在当前代码中设置此 timeToUnload 值,因为我不使用 WorkflowServiceHost。 我应该在每个网络方法中创建一个新的吗?或者做一个单例?

http://social.msdn.microsoft.com/Forums/en-US/3e38a60e-8a99-4c01-a26b-f82670ca5601/instancelockedexception-when-application-restarts-using-persistableidleactionpersist?forum=wfprerelease

-> 在我的商店中以 1 秒的时间跨度试过这个,也没有帮助。

任何建议将不胜感激:-)

跟进

阅读这篇文章后:Error when attempting to Resume a Windows Workflow

我创建了一个 DisposableStore 类,设计如下:

public class DisposableStore : IDisposable
{
private const string ConnectionString = "Server=.\\SQLEXPRESS;Initial Catalog=WF45GettingStartedTutorial;Integrated Security=SSPI";
private SqlWorkflowInstanceStore _store;
private InstanceHandle _handle;

public SqlWorkflowInstanceStore Store
{
get
{
if (_store == null)
{
Debug.WriteLine("Building new store");
_store = new SqlWorkflowInstanceStore(ConnectionString);
StateMachineStateTracker.Promote(_store);

_handle = _store.CreateInstanceHandle();
InstanceView view = _store.Execute(_handle, new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(30));
_store.DefaultInstanceOwner = view.InstanceOwner;
}

return _store;
}
}

public void Dispose()
{
var deleteOwnerCmd = new DeleteWorkflowOwnerCommand();
Store.Execute(_handle, deleteOwnerCmd, TimeSpan.FromSeconds(30));
}
}

我按如下方式使用它:

[WebMethod]
public bool Resume(Guid instanceId, string bookmarkName, object bookmarkParameter)
{
Debug.WriteLine(string.Format("Resume - Service id : {0}", _serviceId));
WorkflowDescriptor descriptor;
using (var store = new DisposableStore())
{
var instance = WorkflowApplication.GetInstance(instanceId, store.Store);
descriptor = WorkflowLocator.GetWorflowFromIdentity(instance.DefinitionIdentity);
}

using (var store = new DisposableStore())
{
var wfApp = new WorkflowApplication(descriptor.Activity, descriptor.Identity);
ConfigureWorkflowApplication(wfApp, store.Store);
wfApp.Load(instanceId);
var sync = new AutoResetEvent(false);
wfApp.Idle = x => sync.Set();
wfApp.Completed = x=> sync.Set();
wfApp.ResumeBookmark(bookmarkName, bookmarkParameter);
sync.WaitOne();
}

return true;
}

使用这种方法,事情变得更好了,这意味着我不再得到 InstanceLockedException,但是现在当 Resume 方法返回到客户端时,我的 wfApp 被中止了:

Exception: System.Runtime.DurableInstancing.InstanceOwnerException The execution of an InstancePersistenceCommand was interrupted because the instance owner registration for owner ID '33ed6492-0685-4f31-8652-4b91acaf50ef' 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

最佳答案

好的,所以我在使用 DisposableStore 的正确轨道上。唯一的问题是商店所有者因为这一行而被过早删除:

wfApp.Idle = x => sync.Set();

这导致我的同步器发布得太快,导致在工作流有机会持久化自身(这需要商店及其所有者)之前调用 dispose 方法(这会杀死商店)。

所以我将这一行替换为:

wfApp.Unloaded = x => sync.Set();

这样,我在释放我的同步器之前等待工作流实例被卸载。

所以对于面临类似问题的人,这里是最终代码的大图:

[WebMethod]
public bool Resume(Guid instanceId, string bookmarkName, object bookmarkParameter)
{
Debug.WriteLine(string.Format("Resume - Service id : {0}", _serviceId));
WorkflowDescriptor descriptor;
using (var store = new DisposableStore())
{
var instance = WorkflowApplication.GetInstance(instanceId, store.Store);
descriptor = WorkflowLocator.GetWorflowFromIdentity(instance.DefinitionIdentity);
}

// We have to create a new store at this point, can't use the same one !!!

using (var store = new DisposableStore())
{
var wfApp = new WorkflowApplication(descriptor.Activity, descriptor.Identity);
ConfigureWorkflowApplication(wfApp, store.Store);
wfApp.Load(instanceId);
var sync = new AutoResetEvent(false);
wfApp.ResumeBookmark(bookmarkName, bookmarkParameter);
wfApp.Unloaded = x => sync.Set();
sync.WaitOne();
}

return true;
}

关于c# - 工作流基础 4.5 InstanceLockedException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22330618/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com