File: System\ServiceModel\Activities\Dispatcher\DurableInstanceManager.cs
Project: ndp\cdf\src\NetFx40\System.ServiceModel.Activities\System.ServiceModel.Activities.csproj (System.ServiceModel.Activities)
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------
 
namespace System.ServiceModel.Activities.Dispatcher
{
    using System.Activities;
    using System.Activities.DurableInstancing;
    using System.Activities.Persistence;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime;
    using System.Runtime.DurableInstancing;
    using System.ServiceModel.Activities.Description;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.Threading;
    using System.Transactions;
    using System.Xml.Linq;
    using System.ServiceModel.Activation;
 
    sealed class DurableInstanceManager
    {
        static AsyncCallback waitAndHandleStoreEventsCallback = Fx.ThunkCallback(new AsyncCallback(WaitAndHandleStoreEventsCallback));
 
        int state;
        InstanceStore store;
        InstanceHandle handle;
        InstanceOwner owner;
        IDictionary<XName, InstanceValue> instanceOwnerMetadata;
        object thisLock;
        IDictionary<XName, InstanceValue> instanceMetadataChanges;
        AsyncWaitHandle waitForStoreEventsLoop;
        WorkflowDefinitionProvider workflowDefinitionProvider;
 
        internal DurableInstanceManager(WorkflowServiceHost host)
        {
            DurableInstancingOptions = new DurableInstancingOptions(this);
            this.instanceOwnerMetadata = new Dictionary<XName, InstanceValue>();
            this.instanceMetadataChanges = new Dictionary<XName, InstanceValue>();
            this.thisLock = new object();
 
            // This is for collision detection.  Will replace with the real service name prior to executing.
            InstanceValue sentinel = new InstanceValue(XNamespace.Get("http://tempuri.org").GetName("Sentinel"));
            this.instanceOwnerMetadata.Add(WorkflowNamespace.WorkflowHostType, sentinel);
            this.instanceMetadataChanges.Add(WorkflowNamespace.WorkflowHostType, sentinel);
            this.instanceMetadataChanges.Add(PersistenceMetadataNamespace.InstanceType, new InstanceValue(WorkflowNamespace.WorkflowHostType, InstanceValueOptions.WriteOnly));
 
            this.Host = host;
        }
 
        WorkflowServiceHost Host { get; set; }
 
        internal PersistenceProviderDirectory PersistenceProviderDirectory { get; set; }
 
        public DurableInstancingOptions DurableInstancingOptions { get; private set; }
 
        public InstanceStore InstanceStore
        {
            get
            {
                return this.store;
            }
            set
            {
                ThrowIfDisposedOrImmutable(this.state);
                this.store = value;
            }
        }
 
        public void AddInstanceOwnerValues(IDictionary<XName, object> readWriteValues, IDictionary<XName, object> writeOnlyValues)
        {
            ThrowIfDisposedOrImmutable(this.state);
 
            if (readWriteValues != null)
            {
                foreach (KeyValuePair<XName, object> property in readWriteValues)
                {
                    if (this.instanceOwnerMetadata.ContainsKey(property.Key))
                    {
                        throw FxTrace.Exception.Argument("readWriteValues", SR.ConflictingValueName(property.Key));
                    }
                    this.instanceOwnerMetadata.Add(property.Key, new InstanceValue(property.Value));
                }
            }
 
            if (writeOnlyValues != null)
            {
                foreach (KeyValuePair<XName, object> property in writeOnlyValues)
                {
                    if (this.instanceOwnerMetadata.ContainsKey(property.Key))
                    {
                        throw FxTrace.Exception.Argument("writeOnlyValues", SR.ConflictingValueName(property.Key));
                    }
                    this.instanceOwnerMetadata.Add(property.Key, new InstanceValue(property.Value,
                        InstanceValueOptions.Optional | InstanceValueOptions.WriteOnly));
                }
            }
        }
 
        public void AddInitialInstanceValues(IDictionary<XName, object> writeOnlyValues)
        {
            ThrowIfDisposedOrImmutable(this.state);
 
            if (writeOnlyValues != null)
            {
                foreach (KeyValuePair<XName, object> pair in writeOnlyValues)
                {
                    if (this.instanceMetadataChanges.ContainsKey(pair.Key))
                    {
                        throw FxTrace.Exception.Argument("writeOnlyValues", SR.ConflictingValueName(pair.Key));
                    }
                    this.instanceMetadataChanges.Add(pair.Key, new InstanceValue(pair.Value, InstanceValueOptions.Optional | InstanceValueOptions.WriteOnly));
                }
            }
        }
 
        static void ThrowIfDisposedOrImmutable(int state)
        {
            if (state == States.Aborted)
            {
                throw FxTrace.Exception.AsError(new CommunicationObjectAbortedException(SR.ServiceHostExtensionAborted));
            }
            if (state == States.Closed)
            {
                throw FxTrace.Exception.AsError(new ObjectDisposedException(typeof(DurableInstanceManager).Name));
            }
            if (state == States.Opened)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ServiceHostExtensionImmutable));
            }
        }
 
        static void ThrowIfClosedOrAborted(int state)
        {
            if (state == States.Aborted)
            {
                throw FxTrace.Exception.AsError(new CommunicationObjectAbortedException(SR.ServiceHostExtensionAborted));
            }
            if (state == States.Closed)
            {
                throw FxTrace.Exception.AsError(new ObjectDisposedException(typeof(DurableInstanceManager).Name));
            }
        }
 
        void InitializePersistenceProviderDirectory()
        {   
            int maxInstances = ServiceThrottlingBehavior.DefaultMaxConcurrentInstances;
            ServiceThrottlingBehavior serviceThrottlingBehavior = Host.Description.Behaviors.Find<ServiceThrottlingBehavior>();
            if (serviceThrottlingBehavior != null)
            {
                maxInstances = serviceThrottlingBehavior.MaxConcurrentInstances;
            }
 
            if (InstanceStore != null)
            {
                PersistenceProviderDirectory = new PersistenceProviderDirectory(InstanceStore, this.owner, this.instanceMetadataChanges, this.workflowDefinitionProvider, Host, DurableConsistencyScope.Global, maxInstances);
            }
            else
            {
                PersistenceProviderDirectory = new PersistenceProviderDirectory(this.workflowDefinitionProvider, Host, maxInstances);
            }
 
            bool aborted;
            lock (this.thisLock)
            {
                aborted = this.state == States.Aborted;
            }
 
            if (aborted)
            {
                if (this.handle != null)
                {
                    this.handle.Free();
                }
 
                PersistenceProviderDirectory.Abort();
            }
 
            // Start listening to store event
            if (InstanceStore != null && !aborted)
            {
                this.waitForStoreEventsLoop = new AsyncWaitHandle(EventResetMode.ManualReset);
                BeginWaitAndHandleStoreEvents(waitAndHandleStoreEventsCallback, this);
            }
        }
 
        IAsyncResult BeginWaitAndHandleStoreEvents(AsyncCallback callback, object state)
        {
            return new WaitAndHandleStoreEventsAsyncResult(this, callback, state);
        }
 
        void EndWaitAndHandleStoreEvents(IAsyncResult result)
        {
            WaitAndHandleStoreEventsAsyncResult.End(result);
        }
 
        static void WaitAndHandleStoreEventsCallback(IAsyncResult result)
        {
            DurableInstanceManager thisPtr = (DurableInstanceManager)result.AsyncState;
            bool stop = false;
            try
            {
                thisPtr.EndWaitAndHandleStoreEvents(result);
            }
            catch (OperationCanceledException exception)
            {
                FxTrace.Exception.AsWarning(exception);
 
                // The OCE, bubbled to this layer, is only from store.BeginWaitForEvents.
                // This indicates handle is freed by 1) normal closing sequence 2) store
                // is dead (eg. lock owner expired).  We will fault the host as well as 
                // cease the loop.
                if (thisPtr.Host.State == CommunicationState.Opening || thisPtr.Host.State == CommunicationState.Opened)
                {
                    thisPtr.Host.Fault(exception);
                }
                stop = true;
            }
            catch (Exception exception)
            {
                if (Fx.IsFatal(exception) || !thisPtr.HandleException(exception))
                {
                    throw;
                }
            }
 
            // Continue
            if (!stop && thisPtr.state == States.Opened)
            {
                thisPtr.BeginWaitAndHandleStoreEvents(waitAndHandleStoreEventsCallback, thisPtr);
            }
            else
            {
                thisPtr.waitForStoreEventsLoop.Set();
            }
        }
 
        bool HandleException(Exception exception)
        {
            if (exception is TimeoutException ||
                exception is OperationCanceledException ||
                exception is TransactionException ||
                exception is CommunicationObjectAbortedException ||
                // When abort raised by WorkflowServiceInstance
                exception is FaultException ||
                exception is InstancePersistenceException)
            {
                FxTrace.Exception.AsWarning(exception);
                this.Host.FaultServiceHostIfNecessary(exception);
                return true;
            }
            return false;
        }
 
        void CheckPersistenceProviderBehavior()
        {
            foreach (IServiceBehavior behavior in Host.Description.Behaviors)
            {
                if (behavior.GetType().FullName == "System.ServiceModel.Description.PersistenceProviderBehavior")
                {
                    throw FxTrace.Exception.AsError(new CommunicationException(SR.UseInstanceStoreInsteadOfPersistenceProvider));
                }
            }
        }
 
        internal IAsyncResult BeginGetInstance(InstanceKey instanceKey, ICollection<InstanceKey> additionalKeys, WorkflowGetInstanceContext parameters, TimeSpan timeout, AsyncCallback callback, object state)
        {
            ThrowIfClosedOrAborted(this.state);
            return new GetInstanceAsyncResult(this, instanceKey, additionalKeys, parameters, timeout, callback, state);
        }
 
        internal IAsyncResult BeginGetInstance(Guid instanceId, WorkflowGetInstanceContext parameters,
            WorkflowIdentityKey updatedIdentity, TimeSpan timeout, AsyncCallback callback, object state)
        {
            ThrowIfClosedOrAborted(this.state);
            return new GetInstanceAsyncResult(this, instanceId, parameters, updatedIdentity, timeout, callback, state);
        }
 
        internal WorkflowServiceInstance EndGetInstance(IAsyncResult result)
        {
            return GetInstanceAsyncResult.End(result);
        }
 
        void AbortDirectory()
        {
            lock (this.thisLock)
            {
                if (this.state == States.Aborted)
                {
                    return;
                }
                this.state = States.Aborted;
            }
 
            if (this.handle != null)
            {
                this.handle.Free();
            }
 
            // PersistenceProviderDirectory is assigned on opened.  Abort could happen before (eg. after created)
            if (PersistenceProviderDirectory != null)
            {
                PersistenceProviderDirectory.Abort();
            }
        }
 
        void SetDefaultOwnerMetadata()
        {
            // Replace the sentinal value with the real scoping name here.
            this.instanceOwnerMetadata[WorkflowNamespace.WorkflowHostType] = new InstanceValue(Host.DurableInstancingOptions.ScopeName);
            this.instanceMetadataChanges[WorkflowNamespace.WorkflowHostType] = new InstanceValue(Host.DurableInstancingOptions.ScopeName);
 
            this.workflowDefinitionProvider.GetDefinitionIdentityMetadata(this.instanceOwnerMetadata);
 
            if (!this.instanceMetadataChanges.ContainsKey(WorkflowServiceNamespace.Service))
            {
                this.instanceMetadataChanges[WorkflowServiceNamespace.Service] = new InstanceValue(Host.ServiceName, InstanceValueOptions.WriteOnly | InstanceValueOptions.Optional);
            }
 
            // add instance metadata about all of our endpoints
            foreach (ServiceEndpoint endpoint in this.Host.Description.Endpoints)
            {
                if (endpoint.Name != null)
                {
                    // treat the control endpoint as special
                    if (endpoint is WorkflowControlEndpoint)
                    {
                        if (!this.instanceOwnerMetadata.ContainsKey(WorkflowServiceNamespace.ControlEndpoint))
                        {
                            this.instanceOwnerMetadata.Add(WorkflowServiceNamespace.ControlEndpoint, new InstanceValue(endpoint.ListenUri));
                        }
                    }
                    else
                    {
                        XName endpointName = WorkflowServiceNamespace.EndpointsPath.GetName(endpoint.Name);
                        if (!this.instanceOwnerMetadata.ContainsKey(endpointName))
                        {
                            this.instanceOwnerMetadata.Add(endpointName, new InstanceValue(endpoint.ListenUri));
                        }
                    }
                }
            }
 
            // as well as additional metadata if we're hosted
            VirtualPathExtension virtualPathExtension = this.Host.Extensions.Find<VirtualPathExtension>();
            if (virtualPathExtension != null && !this.instanceMetadataChanges.ContainsKey(PersistenceMetadataNamespace.ActivationType))
            {
                // Example values for various web-host properties
                // SiteName: "Default Website"
                // RelativeApplicationPath/ApplicationVirtualPath: "/myApp1"
                // Virtual Path: "~/ShoppingCartService/ShoppingCartService.xaml"
                // Relative Service Path: "/myApp1/ShoppingCartService/ShoppingCartService.xaml"
                this.instanceMetadataChanges.Add(PersistenceMetadataNamespace.ActivationType, new InstanceValue(PersistenceMetadataNamespace.ActivationTypes.WAS, InstanceValueOptions.WriteOnly | InstanceValueOptions.Optional));
 
                string siteName = this.Host.OverrideSiteName ? this.Host.Description.Name : virtualPathExtension.SiteName;
                
                // The remaining properties will get overritten if the user set them manually.  To control activation, the user should also set ActivationType, even if just to WAS.
                this.instanceMetadataChanges[WorkflowServiceNamespace.SiteName] = new InstanceValue(siteName, InstanceValueOptions.WriteOnly | InstanceValueOptions.Optional);
                this.instanceMetadataChanges[WorkflowServiceNamespace.RelativeApplicationPath] = new InstanceValue(virtualPathExtension.ApplicationVirtualPath, InstanceValueOptions.WriteOnly | InstanceValueOptions.Optional);
 
                string virtualPath = virtualPathExtension.VirtualPath.Substring(1);
                string relativePath = ("/" == virtualPathExtension.ApplicationVirtualPath) ? virtualPath : virtualPathExtension.ApplicationVirtualPath + virtualPath;
                
                this.instanceMetadataChanges[WorkflowServiceNamespace.RelativeServicePath] = new InstanceValue(relativePath, InstanceValueOptions.WriteOnly | InstanceValueOptions.Optional);
            }
        }
 
        public void Open(TimeSpan timeout)
        {
            Fx.Assert(Host != null, "Extension should have been attached in WorkflowServiceHost constructor.");
 
            lock (this.thisLock)
            {
                ThrowIfDisposedOrImmutable(this.state);
                this.state = States.Opened;
            }
            InitializeDefinitionProvider();
 
            CheckPersistenceProviderBehavior();
 
            SetDefaultOwnerMetadata();
 
 
            if (InstanceStore != null)
            {
                using (new TransactionScope(TransactionScopeOption.Suppress))
                {
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                    InstanceHandle handle = null;
                    try
                    {
                        handle = InstanceStore.CreateInstanceHandle(null);
                        this.owner = InstanceStore.Execute(handle, GetCreateOwnerCommand(), timeoutHelper.RemainingTime()).InstanceOwner;
                        this.handle = handle;
                        handle = null;
                    }
                    catch (InstancePersistenceException exception)
                    {
                        throw FxTrace.Exception.AsError(new CommunicationException(SR.UnableToOpenAndRegisterStore, exception));
                    }
                    finally
                    {
                        if (handle != null)
                        {
                            handle.Free();
                        }
                    }
                }
            }
 
            InitializePersistenceProviderDirectory();
        }
 
        void InitializeDefinitionProvider()
        {
            WorkflowServiceBehavior workflowServiceBehavior = Host.Description.Behaviors.Find<WorkflowServiceBehavior>();
            Fx.Assert(workflowServiceBehavior != null && workflowServiceBehavior.WorkflowDefinitionProvider != null,
                "WorkflowServiceBehavior must be present on WorkflowServiceHost and WorkflowDefinitionProvider must be present on WorkflowServiceBehavior.");
 
            this.workflowDefinitionProvider = workflowServiceBehavior.WorkflowDefinitionProvider;
        }
 
        public IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            Fx.Assert(Host != null, "Extension should have been attached in WorkflowServiceHost constructor.");
 
            using (new TransactionScope(TransactionScopeOption.Suppress))
            {
                return new OpenInstanceStoreAsyncResult(this, timeout, callback, state);
            }
        }
 
        public void EndOpen(IAsyncResult result)
        {
            OpenInstanceStoreAsyncResult.End(result);
        }
 
        public void Close(TimeSpan timeout)
        {
            // We normally would have a purely synchronous path for our synchronous
            // overload, but PersistenceIOParticipant.OnBeginSave() doesn't have a synchronous counterpart.
            // Given that, at the very least we'd have to do PersistencePipeline.EndSave(PersistencePipeline.BeginSave).
            // Therefore we resign ourselves to End(Begin) and take comfort in the unification of logic by not having two codepaths
            CloseAsyncResult.End(new CloseAsyncResult(this, timeout, null, null));
        }
 
        public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new CloseAsyncResult(this, timeout, callback, state);
        }
 
        public void EndClose(IAsyncResult result)
        {
            CloseAsyncResult.End(result);
        }
 
        public void Abort()
        {
            AbortDirectory();
        }
 
        InstancePersistenceCommand GetCreateOwnerCommand()
        {
            InstancePersistenceCommand command;
            IDictionary<XName, InstanceValue> commandMetadata;
            if (this.instanceOwnerMetadata.ContainsKey(Workflow45Namespace.DefinitionIdentities))
            {
                CreateWorkflowOwnerWithIdentityCommand withIdentity = new CreateWorkflowOwnerWithIdentityCommand();
                command = withIdentity;
                commandMetadata = withIdentity.InstanceOwnerMetadata;
            }
            else
            {
                CreateWorkflowOwnerCommand withoutIdentity = new CreateWorkflowOwnerCommand();
                command = withoutIdentity;
                commandMetadata = withoutIdentity.InstanceOwnerMetadata;
            }
 
            foreach (KeyValuePair<XName, InstanceValue> metadata in this.instanceOwnerMetadata)
            {
                commandMetadata.Add(metadata);
            }
 
            return command;
        }
 
        static class States
        {
            public const int Created = 0;
            public const int Opened = 1;
            public const int Closed = 2;
            public const int Aborted = 3;
        }
 
        class OpenInstanceStoreAsyncResult : AsyncResult
        {
            static AsyncCompletion handleEndExecute = new AsyncCompletion(HandleEndExecute);
            static Action<AsyncResult, Exception> onFinally = new Action<AsyncResult, Exception>(OnFinally);
 
            DurableInstanceManager instanceManager;
            TimeoutHelper timeoutHelper;
            InstanceHandle handle;
 
            public OpenInstanceStoreAsyncResult(DurableInstanceManager instanceManager, TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.instanceManager = instanceManager;
                this.timeoutHelper = new TimeoutHelper(timeout);
 
                lock (this.instanceManager.thisLock)
                {
                    DurableInstanceManager.ThrowIfDisposedOrImmutable(this.instanceManager.state);
                    this.instanceManager.state = States.Opened;
                }
 
                this.instanceManager.InitializeDefinitionProvider();
 
                instanceManager.CheckPersistenceProviderBehavior();
 
                this.instanceManager.SetDefaultOwnerMetadata();
 
                this.OnCompleting = OpenInstanceStoreAsyncResult.onFinally;
 
                bool completeSelf;
                Exception completionException = null;
                try
                {
                    if (instanceManager.InstanceStore == null)
                    {
                        completeSelf = CreateDirectory();
                    }
                    else
                    {
                        this.handle = this.instanceManager.InstanceStore.CreateInstanceHandle(null);
                        IAsyncResult executeResult = this.instanceManager.InstanceStore.BeginExecute(this.handle,
                            this.instanceManager.GetCreateOwnerCommand(), this.timeoutHelper.RemainingTime(),
                            this.PrepareAsyncCompletion(OpenInstanceStoreAsyncResult.handleEndExecute), this);
                        completeSelf = SyncContinue(executeResult);
                    }
                }
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception))
                    {
                        throw;
                    }
 
                    completionException = exception;
                    completeSelf = true;
                }
                if (completeSelf)
                {
                    Complete(true, completionException);
                }
            }
 
            static bool HandleEndExecute(IAsyncResult result)
            {
                OpenInstanceStoreAsyncResult thisPtr = (OpenInstanceStoreAsyncResult)result.AsyncState;
 
                thisPtr.instanceManager.owner = thisPtr.instanceManager.InstanceStore.EndExecute(result).InstanceOwner;
 
                return thisPtr.CreateDirectory();
            }
 
            static void OnFinally(AsyncResult result, Exception exception)
            {
                if (exception != null)
                {
                    try
                    {
                        if (exception is InstancePersistenceException)
                        {
                            throw FxTrace.Exception.AsError(new CommunicationException(SR.UnableToOpenAndRegisterStore, exception));
                        }
                    }
                    finally
                    {
                        OpenInstanceStoreAsyncResult thisPtr = (OpenInstanceStoreAsyncResult)result;
                        if (thisPtr.handle != null)
                        {
                            thisPtr.handle.Free();
                        }
                    }
                }
            }
 
            public static void End(IAsyncResult result)
            {
                AsyncResult.End<OpenInstanceStoreAsyncResult>(result);
            }
 
            bool CreateDirectory()
            {
                this.instanceManager.InitializePersistenceProviderDirectory();
                this.instanceManager.handle = this.handle;
                this.handle = null;
                return true;
            }
        }
 
        class CloseAsyncResult : AsyncResult
        {
            static AsyncCallback handleEndReleaseInstanceWrapperCallback = Fx.ThunkCallback(new AsyncCallback(HandleEndReleaseInstanceWrapperCallback));
            static AsyncCompletion handleEndExecute = new AsyncCompletion(HandleEndExecute);
            static Action<object, TimeoutException> handleWaitForStoreEvents = new Action<object, TimeoutException>(HandleWaitForStoreEvents);
            static int outstandingUnloadCapacity = 10;
 
            TimeoutHelper timeoutHelper;
            DurableInstanceManager instanceManager;
            IEnumerator<PersistenceContext> workflowServiceInstances;
            int instanceCount;
            InstanceHandle handle;
 
            object instanceQueueLock;
            int completedUnloadCount;
            bool allReleaseInstancesCompletedSynchronously;
 
            public CloseAsyncResult(DurableInstanceManager instanceManager, TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.instanceManager = instanceManager;
                this.timeoutHelper = new TimeoutHelper(timeout);
                this.instanceQueueLock = new object();
                this.allReleaseInstancesCompletedSynchronously = true;
 
                if (this.instanceManager.state == States.Opened && this.instanceManager.handle != null)
                {
                    // Note: since we change state before actual openning, this may 
                    // get NullRef (---- already exists in other places) if Close 
                    // is called on an unsuccessful or incompleted opened DIM.  
                    // Assuming it is a non supported scenario.  
                    this.instanceManager.handle.Free();
                    if (WaitForStoreEventsLoop())
                    {
                        Complete(true);
                    }
                }
                else
                {
                    if (PerformClose())
                    {
                        Complete(true);
                    }
                }
            }
 
            bool PerformClose()
            {
                bool closed;
                bool opened;
                bool aborted;
 
                lock (this.instanceManager.thisLock)
                {
                    closed = this.instanceManager.state == States.Closed;
                    opened = this.instanceManager.state == States.Opened;
                    aborted = this.instanceManager.state == States.Aborted;
                    if (opened)
                    {
                        this.instanceManager.state = States.Closed;
                    }
                }
 
                if (closed)
                {
                    return true;
                }
                if (!opened)
                {
                    if (!aborted)
                    {
                        this.instanceManager.AbortDirectory();
                    }
 
                    // We cannot throw here if the DurableInstanceManager is already aborted since service host could 
                    // be aborted due to a timeout exception. Simply return here
                    return true;
                }
 
                IEnumerable<PersistenceContext> contexts = this.instanceManager.PersistenceProviderDirectory.GetContexts();
                this.instanceCount = contexts.Count<PersistenceContext>();
                this.workflowServiceInstances = contexts.GetEnumerator();
                // We only call StartProcess if we actually have instances to release.
                if (this.instanceCount > 0)
                {
                    StartProcess();
                }
                else
                {
                    // No instances to release. Do the post processing.
                    return PostProcess();
                }
 
                return false;
            }
 
            bool WaitForStoreEventsLoop()
            {
                // Event never get initialized, meaning we have not started the WaitForStoreEvents loop
                if (this.instanceManager.waitForStoreEventsLoop == null
                    || this.instanceManager.waitForStoreEventsLoop.WaitAsync(handleWaitForStoreEvents, this, this.timeoutHelper.RemainingTime()))
                {
                    return PerformClose();
                }
                else
                {
                    return false;
                }
            }
 
            static void HandleWaitForStoreEvents(object state, TimeoutException exception)
            {
                CloseAsyncResult thisPtr = (CloseAsyncResult)state;
                if (exception != null)
                {
                    thisPtr.Complete(false, exception);
                    return;
                }
 
                bool completeSelf = false;
                Exception completionException = null;
 
                try
                {
                    completeSelf = thisPtr.PerformClose();
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
                    completionException = exception;
                    completeSelf = true;
                }
 
                if (completeSelf)
                {
                    thisPtr.Complete(false, completionException);
                }
            }
 
            void StartProcess()
            {
                for (int i = 0; i < outstandingUnloadCapacity; i++)
                {
                    if (!Process())
                    {
                        break;
                    }
                }
            }
 
            bool Process()
            {
                bool shouldContinueProcess;
                WorkflowServiceInstance currentInstance = null;
 
                lock (this.instanceQueueLock)
                {
                    if (this.workflowServiceInstances.MoveNext())
                    {
                        currentInstance = this.workflowServiceInstances.Current.GetInstance(null);
                        shouldContinueProcess = true;
                    }
                    else
                    {
                        shouldContinueProcess = false;
                    }
                }
 
                if (shouldContinueProcess)
                {
                    if (currentInstance != null)
                    {
                        try
                        {
                            // Our own wrapper callback will invoke the inner callback even when result is completed synchronously
                            IAsyncResult result = currentInstance.BeginReleaseInstance(
                                false,
                                this.timeoutHelper.RemainingTime(),
                                CloseAsyncResult.handleEndReleaseInstanceWrapperCallback,
                                this);
                        }
                        catch (Exception e)
                        {
                            if (Fx.IsFatal(e))
                            {
                                throw;
                            }
 
                            // Ignore exception thrown from BeginReleaseInstance.
                            // We do not complete CloseAsyncResult with this exception.
                            // Instead, we want to keep this thread running so that it can clean up other instances.
                            FxTrace.Exception.AsWarning(e);
                        }
                    }
                    else
                    {
                        if (Interlocked.Increment(ref this.completedUnloadCount) == this.instanceCount)
                        {
                            // We are done with the instances, so do post-processing. If that completes
                            // synchronously, we need to call Complete. We completed synchronously if all
                            // of the ReleaseInstance invocations completed synchronously.
                            // The return value from this method only indicates
                            // if there are more instances to deal with, not if we are Complete.
                            if (PostProcess())
                            {
                                Complete(this.allReleaseInstancesCompletedSynchronously);
                            }
                        }
                    }
                }
 
                return shouldContinueProcess;
            }
 
            bool PostProcess()
            {
                //cleanup any buffered receives unassociated with workflowServiceInstances
                BufferedReceiveManager bufferedReceiveManager = this.instanceManager.Host.Extensions.Find<BufferedReceiveManager>();
                if (bufferedReceiveManager != null)
                {
                    bufferedReceiveManager.AbandonBufferedReceives();
                }
 
                // Send the DeleteWorkflowOwner command to the instance store.
                if (this.instanceManager.InstanceStore != null)
                {
                    IAsyncResult executeResult = null;
                    this.handle = this.instanceManager.InstanceStore.CreateInstanceHandle(this.instanceManager.owner);
                    try
                    {
                        executeResult = this.instanceManager.InstanceStore.BeginExecute(this.handle,
                            new DeleteWorkflowOwnerCommand(), this.timeoutHelper.RemainingTime(),
                            this.PrepareAsyncCompletion(CloseAsyncResult.handleEndExecute), this);
                        return (SyncContinue(executeResult));
                    }
                    // Ignore some exceptions because DeleteWorkflowOwner is best effort.
                    catch (InstancePersistenceCommandException) { }
                    catch (InstanceOwnerException) { }
                    catch (OperationCanceledException) { }
                    finally
                    {
                        if (executeResult == null)
                        {
                            this.handle.Free();
                            this.handle = null;
                        }
                    }
                    return this.SyncContinue(executeResult);
                }
                else
                {
                    CloseProviderDirectory();
                    return true;
                }
            }
 
            static void HandleEndReleaseInstance(IAsyncResult result)
            {
                CloseAsyncResult thisPtr = (CloseAsyncResult)result.AsyncState;
                thisPtr.allReleaseInstancesCompletedSynchronously = thisPtr.allReleaseInstancesCompletedSynchronously && result.CompletedSynchronously;
                try
                {
                    WorkflowServiceInstance.EndReleaseInstanceForClose(result);
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    // Ignore exception thrown from ReleaseInstanceAsyncResult.End.
                    // We do not complete CloseAsyncResult with this exception.
                    // Instead, we want to keep this thread running so that it can clean up other instances.
                    FxTrace.Exception.AsWarning(e);
                }
 
                if (Interlocked.Increment(ref thisPtr.completedUnloadCount) == thisPtr.instanceCount)
                {
                    if (thisPtr.PostProcess())
                    {
                        // If PostProcess completed synchronously, then the entire CloseAsyncResult is complete.
                        // Whether or not we completed syncrhonously depends on if all the ReleaseInstance invocations completed
                        // synchronously.
                        thisPtr.Complete(thisPtr.allReleaseInstancesCompletedSynchronously);
                    }
                }
                else
                {
                    thisPtr.Process();
                }
            }
 
            void CloseProviderDirectory()
            {
                bool success = false;
                try
                {
                    this.instanceManager.PersistenceProviderDirectory.Close();
                    success = true;
                }
                finally
                {
                    if (!success)
                    {
                        this.instanceManager.AbortDirectory();
                    }
                }
            }
 
            static bool HandleEndExecute(IAsyncResult result)
            {
                CloseAsyncResult thisPtr = (CloseAsyncResult)result.AsyncState;
 
                try
                {
                    thisPtr.instanceManager.owner = thisPtr.instanceManager.InstanceStore.EndExecute(result).InstanceOwner;
                }
                // Ignore some exceptions because DeleteWorkflowOwner is best effort.
                catch (InstancePersistenceCommandException) { }
                catch (InstanceOwnerException) { }
                catch (OperationCanceledException) { }
                finally
                {
                    thisPtr.handle.Free();
                    thisPtr.handle = null;
                }
 
                thisPtr.CloseProviderDirectory();
                return true;
            }
 
            public static void End(IAsyncResult result)
            {
                AsyncResult.End<CloseAsyncResult>(result);
            }
 
            static void HandleEndReleaseInstanceWrapperCallback(IAsyncResult result)
            {
                Fx.Assert(result != null, "Async result cannot be null!");
 
                CloseAsyncResult thisPtr = (CloseAsyncResult)result.AsyncState;
 
                Exception completionException = null;
                try
                {
                    HandleEndReleaseInstance(result);
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    completionException = e;
                }
 
                // Exceptions thrown from Process and process callback should be handled in those methods respectively.
                // The only exception that can get here should be exception thrown from PostProcess.
                // PostProcess is guaranteed to be called only once.
                if (completionException != null)
                {
                    thisPtr.Complete(false, completionException);
                }
            }
        }
 
        // Need to ensure that any failure in the methods of GetInstanceAsyncResult after a WorkflowServiceInstance has been acquired
        // results in one of three outcomes, namely :
        // - the WorkflowServiceInstance is set to null
        // - the WorkflowServiceInstance is aborted
        // - ReleaseReference is called on the WorkflowServiceInstance to ensure that unload happens 
        //   (ultimately resulting in the WorkflowServiceInstance being aborted)
        // This is to prevent leaking WorkflowServiceInstances since nothing else has a handle to the WorkflowServiceInstance in those
        // scenarios.
 
        class GetInstanceAsyncResult : TransactedAsyncResult
        {
            static AsyncCompletion handleEndAcquireReference = new AsyncCompletion(HandleEndAcquireReference);
            static AsyncCompletion handleEndLoad = new AsyncCompletion(HandleEndLoad);
            static AsyncCompletion handleAssociateInfrastructureKeys = new AsyncCompletion(HandleAssociateInfrastructureKeys);
            static AsyncCompletion handleCommit = new AsyncCompletion(HandleCommit);
            static AsyncCompletion handleEndEnlistContext = new AsyncCompletion(HandleEndEnlistContext);
            static Action<AsyncResult, Exception> onCompleting = new Action<AsyncResult, Exception>(Finally);
 
            DurableInstanceManager instanceManager;
            Guid instanceId;
            InstanceKey instanceKey;
            ICollection<InstanceKey> additionalKeys;
            TimeSpan timeout;
            WorkflowServiceInstance durableInstance;
            bool referenceAcquired;
            PersistenceContext persistenceContext;
            WorkflowGetInstanceContext parameters;
            DependentTransaction transaction;
            CommittableTransaction committableTransaction;
            bool loadAny;
            WorkflowIdentityKey updatedIdentity;
 
            public GetInstanceAsyncResult(DurableInstanceManager instanceManager, InstanceKey instanceKey, ICollection<InstanceKey> additionalKeys, WorkflowGetInstanceContext parameters,
                TimeSpan timeout, AsyncCallback callback, object state)
                : this(instanceManager, parameters, timeout, callback, state)
            {
                Fx.Assert(instanceKey != null, "Instance key must be set.");
 
                this.instanceKey = instanceKey;
                this.additionalKeys = additionalKeys;
 
                if (this.GetInstance())
                {
                    this.Complete(true);
                }
            }
 
            public GetInstanceAsyncResult(DurableInstanceManager instanceManager, Guid instanceId, WorkflowGetInstanceContext parameters, WorkflowIdentityKey updatedIdentity,
                TimeSpan timeout, AsyncCallback callback, object state)
                : this(instanceManager, parameters, timeout, callback, state)
            {
                this.instanceId = instanceId;
                this.updatedIdentity = updatedIdentity;
 
                if (this.GetInstance())
                {
                    this.Complete(true);
                }
            }
 
            GetInstanceAsyncResult(DurableInstanceManager instanceManager, WorkflowGetInstanceContext parameters,
                TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.instanceManager = instanceManager;
                this.parameters = parameters;
                this.timeout = timeout;
                this.loadAny = parameters == null;
                this.OnCompleting = onCompleting;
 
                Transaction currentTransaction = Transaction.Current;
                if (currentTransaction == null && this.instanceManager.Host.IsLoadTransactionRequired)
                {
                    this.committableTransaction = new CommittableTransaction(this.timeout);
                    currentTransaction = committableTransaction;
                }
                if (currentTransaction != null)
                {
                    this.transaction = currentTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
                }
            }
 
            public static WorkflowServiceInstance End(IAsyncResult result)
            {
                return AsyncResult.End<GetInstanceAsyncResult>(result).durableInstance;
            }
 
            bool TryAcquire(bool fromCache)
            {
                this.durableInstance = this.persistenceContext.GetInstance(this.parameters);
 
                if (!fromCache)
                {
                    this.referenceAcquired = true;
                    return AssociateKeys();
                }
 
                IAsyncResult nextResult = this.durableInstance.BeginTryAcquireReference(this.timeout, this.PrepareAsyncCompletion(handleEndAcquireReference), this);
                return SyncContinue(nextResult);
            }
 
            static bool HandleEndAcquireReference(IAsyncResult result)
            {
                GetInstanceAsyncResult thisPtr = (GetInstanceAsyncResult)result.AsyncState;
 
                if (thisPtr.durableInstance.EndTryAcquireReference(result))
                {
                    thisPtr.referenceAcquired = true;
                    return thisPtr.TryEnlistContext();
                }
                else
                {
                    //We have to re-dispense this Durable Instance this is not usable.
                    thisPtr.referenceAcquired = false;
                    thisPtr.durableInstance = null;
                    return thisPtr.GetInstance();
                }
            }
 
            bool TryEnlistContext()
            {
                IAsyncResult enlistResult = null;
                bool tryAgain = false;
 
                // We need to enlist for the transaction. This call will wait until
                // we obtain the transaction lock on the PersistenceContext, too. If there is no current transaction, this call
                // will still wait to get the transaction lock, but we not create an enlistment.
                using (PrepareTransactionalCall(this.transaction))
                {
                    try
                    {
                        enlistResult = this.persistenceContext.BeginEnlist(this.timeout, PrepareAsyncCompletion(handleEndEnlistContext), this);
                    }
                    catch (ObjectDisposedException)
                    {
                        tryAgain = true;
                    }
                    catch (CommunicationObjectAbortedException)
                    {
                        throw FxTrace.Exception.AsError(new OperationCanceledException(SR.DefaultAbortReason));
                    }
                }
 
                if (tryAgain)
                {
                    this.referenceAcquired = false;
                    this.durableInstance = null;
                    return this.GetInstance();
                }
                else
                {
                    return SyncContinue(enlistResult);
                }
            }
 
            static bool HandleEndEnlistContext(IAsyncResult result)
            {
                GetInstanceAsyncResult thisPtr = (GetInstanceAsyncResult)result.AsyncState;
 
                // 
 
                try
                {
                    thisPtr.persistenceContext.EndEnlist(result);
                }
                catch (ObjectDisposedException)
                {
                    // It's possible that the PersistenceContext was closed and removed from the cache
                    // while we were queued up for it. In that situation, this call to EndEnlist will
                    // throw an ObjectDisposedException because the PersistenceContext is in the closed
                    // state. If that happens, we need to try the load again from the beginning.
                    thisPtr.referenceAcquired = false;
                    thisPtr.durableInstance = null;
                    return thisPtr.GetInstance();
                }
                catch (CommunicationObjectAbortedException)
                {
                    throw FxTrace.Exception.AsError(new OperationCanceledException(SR.DefaultAbortReason));
                }
 
                return thisPtr.AssociateKeys();
            }
 
            bool GetInstance()
            {
                IAsyncResult nextResult = null;
 
                if (!this.loadAny && this.parameters.CanCreateInstance)
                {
                    Fx.Assert(this.updatedIdentity == null, "Update() can never create instance. Enable this path if we ever support updating via user-defined operation.");
                    if (this.instanceKey != null && this.instanceKey.IsValid)
                    {
                        nextResult = this.instanceManager.PersistenceProviderDirectory.BeginLoadOrCreate(
                            this.instanceKey, Guid.Empty, this.additionalKeys, this.transaction,
                            this.timeout, PrepareAsyncCompletion(handleEndLoad), this);
                    }
                    else
                    {
                        // Either invalid key (new instance) or lookup by instance ID.
                        nextResult = this.instanceManager.PersistenceProviderDirectory.BeginLoadOrCreate(
                            this.instanceId, this.additionalKeys, this.transaction,
                            this.timeout, PrepareAsyncCompletion(handleEndLoad), this);
                    }
                }
                else
                {
                    if (this.instanceKey != null)
                    {
                        Fx.Assert(this.updatedIdentity == null, "Update() always has the instance ID. Enable this path if we ever support updating via user-defined operation that relies on correlation.");
                        nextResult = this.instanceManager.PersistenceProviderDirectory.BeginLoad(
                            this.instanceKey, this.additionalKeys, this.transaction,
                            this.timeout, PrepareAsyncCompletion(handleEndLoad), this);
                    }
                    else
                    {
                        nextResult = this.instanceManager.PersistenceProviderDirectory.BeginLoad(
                            this.instanceId, null, this.transaction, this.loadAny, this.updatedIdentity,
                            this.timeout, PrepareAsyncCompletion(handleEndLoad), this);
                    }
                }
                return SyncContinue(nextResult);
            }
 
            bool AssociateKeys()
            {
                if (this.additionalKeys != null && this.additionalKeys.Count > 0)
                {
                    IAsyncResult result;
                    try
                    {
                        result = this.durableInstance.BeginAssociateInfrastructureKeys(this.additionalKeys, this.transaction, this.timeout,
                                PrepareAsyncCompletion(handleAssociateInfrastructureKeys), this);
                    }
                    catch (Exception exception)
                    {
                        if (Fx.IsFatal(exception))
                        {
                            throw;
                        }
                        this.persistenceContext.Abort();
                        throw;
                    }
 
                    return SyncContinue(result);
                }
                else
                {
                    return CommitTransaction();
                }
            }
 
            static bool HandleEndLoad(IAsyncResult result)
            {
                GetInstanceAsyncResult thisPtr = (GetInstanceAsyncResult)result.AsyncState;
 
                PersistenceContext previousPersistenceContext = thisPtr.persistenceContext;
                bool fromCache;
                if (!thisPtr.loadAny && thisPtr.parameters.CanCreateInstance)
                {
                    thisPtr.persistenceContext = thisPtr.instanceManager.PersistenceProviderDirectory.EndLoadOrCreate(result, out fromCache);
                }
                else
                {
                    thisPtr.persistenceContext = thisPtr.instanceManager.PersistenceProviderDirectory.EndLoad(result, out fromCache);
                }
                Fx.AssertAndThrow(previousPersistenceContext != thisPtr.persistenceContext, "PPD should not load same PersistenceContext for the same GetInstanceAsyncResult!");
                return thisPtr.TryAcquire(fromCache);
            }
 
            static bool HandleAssociateInfrastructureKeys(IAsyncResult result)
            {
                GetInstanceAsyncResult thisPtr = (GetInstanceAsyncResult)result.AsyncState;
 
                try
                {
                    thisPtr.durableInstance.EndAssociateInfrastructureKeys(result);
                }
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception))
                    {
                        throw;
                    }
                    thisPtr.persistenceContext.Abort();
                    throw;
                }
 
                return thisPtr.CommitTransaction();
            }
 
            bool CommitTransaction()
            {
                if (this.transaction != null)
                {
                    this.transaction.Complete();
                }
                if (this.committableTransaction != null)
                {
                    IAsyncResult result = this.committableTransaction.BeginCommit(PrepareAsyncCompletion(handleCommit), this);
                    return SyncContinue(result);
                }
                else
                {
                    return true;
                }
            }
 
            static bool HandleCommit(IAsyncResult result)
            {
                GetInstanceAsyncResult thisPtr = (GetInstanceAsyncResult)result.AsyncState;
                thisPtr.committableTransaction.EndCommit(result);
                thisPtr.committableTransaction = null;
                return true;
            }
 
            static void Finally(AsyncResult result, Exception exception)
            {
                GetInstanceAsyncResult thisPtr = (GetInstanceAsyncResult)result;
 
                if (thisPtr.committableTransaction != null)
                {
                    Fx.Assert(exception != null, "Shouldn't get here in the success case.");
 
                    try
                    {
                        thisPtr.committableTransaction.Rollback(exception);
                    }
                    catch (Exception rollbackException)
                    {
                        if (Fx.IsFatal(rollbackException))
                        {
                            throw;
                        }
                        FxTrace.Exception.AsWarning(rollbackException);
                    }
                }
 
                // Reference is acquired on an instance but we fail perform subsequent task before
                // return an instance to the client (Tx Enlist timeout).  We are responsible to 
                // release the reference.  We don't need to worry about Aborted or other State (has
                // no effect on ref counting).
                if (thisPtr.referenceAcquired && exception != null)
                {
                    Fx.Assert(thisPtr.durableInstance != null, "durableInstance must not be null!");
                    thisPtr.durableInstance.ReleaseReference();
                }
            }
        }
 
        // This async result waits for store events and handle them (currently only support HasRunnableWorkflowEvent).
        // It is intended to always complete async to simplify caller usage. 
        // 1) no code to handle sync completion. 
        // 2) recursive call will be safe from StackOverflow.
        // For simplicity, we handle (load/run) each event one-by-one.
        // We ---- certain set of exception (see HandleException).  Other will crash the process.
        // InvalidOperation is also handled due to TryLoadRunnableWorkflowCommand could fail if ---- with other hosts.
        class WaitAndHandleStoreEventsAsyncResult : AsyncResult
        {
            static Action<object> waitAndHandleStoreEvents = new Action<object>(WaitAndHandleStoreEvents);
            static AsyncCompletion handleEndWaitForStoreEvents = new AsyncCompletion(HandleEndWaitForStoreEvents);
            static AsyncCompletion handleEndGetInstance = new AsyncCompletion(HandleEndGetInstance);
            static AsyncCompletion handleEndRunInstance = new AsyncCompletion(HandleEndRunInstance);
 
            DurableInstanceManager instanceManager;
            IEnumerator<InstancePersistenceEvent> events;
            WorkflowServiceInstance currentInstance;
 
            public WaitAndHandleStoreEventsAsyncResult(DurableInstanceManager instanceManager, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.instanceManager = instanceManager;
                ActionItem.Schedule(waitAndHandleStoreEvents, this);
            }
 
            public static void End(IAsyncResult result)
            {
                AsyncResult.End<WaitAndHandleStoreEventsAsyncResult>(result);
            }
 
            static void WaitAndHandleStoreEvents(object state)
            {
                WaitAndHandleStoreEventsAsyncResult thisPtr = (WaitAndHandleStoreEventsAsyncResult)state;
 
                bool completeSelf;
                Exception completionException = null;
                try
                {
                    completeSelf = thisPtr.WaitForStoreEvents();
                }
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception))
                    {
                        throw;
                    }
 
                    completionException = exception;
                    completeSelf = true;
                }
 
                if (completeSelf)
                {
                    thisPtr.Complete(false, completionException);
                }
            }
 
            bool WaitForStoreEvents()
            {
                // Defense in depth with a predefined timeout
                IAsyncResult result = this.instanceManager.InstanceStore.BeginWaitForEvents(this.instanceManager.handle, 
                    TimeSpan.FromSeconds(600), PrepareAsyncCompletion(handleEndWaitForStoreEvents), this);
                return SyncContinue(result);
            }
 
            static bool HandleEndWaitForStoreEvents(IAsyncResult result)
            {
                WaitAndHandleStoreEventsAsyncResult thisPtr = (WaitAndHandleStoreEventsAsyncResult)result.AsyncState;
                thisPtr.events = thisPtr.instanceManager.InstanceStore.EndWaitForEvents(result).GetEnumerator();
                return thisPtr.HandleStoreEvents();
            }
 
            bool HandleStoreEvents()
            {
                if (!this.events.MoveNext())
                {
                    return true;
                }
 
                InstancePersistenceEvent currentEvent = this.events.Current;
                if (currentEvent.Name == HasRunnableWorkflowEvent.Value.Name)
                {
                    try
                    {
                        IAsyncResult result = this.instanceManager.BeginGetInstance(Guid.Empty, null, null, this.instanceManager.Host.PersistTimeout,
                            PrepareAsyncCompletion(handleEndGetInstance), this);
                        return SyncContinue(result);
                    }
                    catch (Exception exception)
                    {
                        if (Fx.IsFatal(exception) || !this.instanceManager.HandleException(exception))
                        {
                            throw;
                        }
                    }
                }
                else
                {
                    Fx.AssertAndThrow("Unknown InstancePersistenceEvent (" + currentEvent.Name + ")!");
                }
 
                return HandleStoreEvents();
            }
 
            static bool HandleEndGetInstance(IAsyncResult result)
            {
                WaitAndHandleStoreEventsAsyncResult thisPtr = (WaitAndHandleStoreEventsAsyncResult)result.AsyncState;
                try
                {
                    thisPtr.currentInstance = thisPtr.instanceManager.EndGetInstance(result);
                    return thisPtr.RunInstance();
                }
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception) || !thisPtr.instanceManager.HandleException(exception))
                    {
                        throw;
                    }
                }
                return thisPtr.HandleStoreEvents();
            }
 
            bool RunInstance()
            {
                try
                {
                    IAsyncResult result = this.currentInstance.BeginRun(null, TimeSpan.MaxValue, PrepareAsyncCompletion(handleEndRunInstance), this);
                    return SyncContinue(result);
                }
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception))
                    {
                        throw;
                    }
                    if (this.currentInstance != null)
                    {
                        this.currentInstance.ReleaseReference();
                        this.currentInstance = null;
                    }
                    if (!this.instanceManager.HandleException(exception))
                    {
                        throw;
                    }
                }
                return HandleStoreEvents();
            }
 
            static bool HandleEndRunInstance(IAsyncResult result)
            {
                WaitAndHandleStoreEventsAsyncResult thisPtr = (WaitAndHandleStoreEventsAsyncResult)result.AsyncState;
                try
                {
                    thisPtr.currentInstance.EndRun(result);
                }
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception) || !thisPtr.instanceManager.HandleException(exception))
                    {
                        throw;
                    }
                }
                finally
                {
                    thisPtr.currentInstance.ReleaseReference();
                    thisPtr.currentInstance = null;
                }
                return thisPtr.HandleStoreEvents();
            }
        }
    }
}