繁体   English   中英

Workflow Foundation 4.5 InstanceLockedException

[英]Workflow Foundation 4.5 InstanceLockedException

我目前正在在客户端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

InstancePersistenceCommand的执行被中断,因为实例“ a1bcbd11-50fc-4a72-b5d2-87b71d0c3c45”已由其他实例所有者锁定。 通常会发生此错误,因为其他主机已加载了实例。 实例上具有锁定的所有者或主机的实例所有者ID为“ 190ea0d9-788f-4278-883e-84226f5788bc”。

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

那我在这里做错了什么?

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

InstanceLockedException:如何处理WF 4.0的锁定问题?

->看起来像我遇到的问题,但是由于我不使用WorkflowServiceHost,所以我不确定如何在当前代码中设置此timeToUnload值。 我应该在每个网络方法中创建一个新方法吗? 还是单身?

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

->在我的商店中尝试使用1秒的时间跨度,也没有帮助。

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

跟进

阅读本文后: 尝试恢复Windows工作流时出错

我创建了一个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被中止了:

异常:System.Runtime.DurableInstancing.InstanceOwnerException由于所有者ID为'33ed6492-0685-4f31-8652-4b91acaf50ef'的实例所有者注册已无效,因此InstancePersistenceCommand的执行被中断。 此错误表明,此所有者锁定的所有实例的内存中副本已过时,应与InstanceHandles一起丢弃。 通常,最好通过重新启动主机来解决此错误

好的,所以我使用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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM