簡體   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