// Created for ref. 20575
        internal void PostPersist(bool isPersistSuccessful)
        {
            // If persist is unsuccessful, we'll undo the changes done
            //   because of the call to .Complete() in PrePresist
            if (!isPersistSuccessful)
            {
                Debug.Assert(rootWorkflowExecutor.CurrentAtomicActivity != null);
                Debug.Assert(pendingQueueStateSnapshot != null);
                Debug.Assert(persistedQueueStatesSnapshot != null);

                TransactionalProperties transactionalProperties = rootWorkflowExecutor.CurrentAtomicActivity.GetValue(WorkflowExecutor.TransactionalPropertiesProperty) as TransactionalProperties;
                Debug.Assert(transactionalProperties != null);

                // Restore queuing states and set root activity's dependency properties to the new values.
                pendingQueueState    = pendingQueueStateSnapshot;
                persistedQueueStates = persistedQueueStatesSnapshot;
                rootWorkflowExecutor.RootActivity.SetValue(WorkflowQueuingService.RootPersistedQueueStatesProperty, persistedQueueStatesSnapshot);
                rootWorkflowExecutor.RootActivity.SetValue(WorkflowQueuingService.PendingMessagesProperty, pendingQueueStateSnapshot.Messages);

                // Also call Subscribe...() because the .Complete() call called Unsubscribe
                transactionalProperties.LocalQueuingService.SubscribeForRootMessageDelivery();
            }

            // The backups are no longer necessary.
            // The next call to PrePresistQueuingServiceState() will do a re-backup.
            persistedQueueStatesSnapshot = null;
            pendingQueueStateSnapshot    = null;
        }
        // Created for ref. 20575
        internal void PrePersist()
        {
            if (rootWorkflowExecutor.CurrentAtomicActivity != null)
            {
                // Create transactionalProperties from currentAtomicActivity
                TransactionalProperties transactionalProperties = this.rootWorkflowExecutor.CurrentAtomicActivity.GetValue(WorkflowExecutor.TransactionalPropertiesProperty) as TransactionalProperties;

                // Create backup snapshot of root queuing service's persistedQueuesStates
                // qService.persistedQueueStates is changed when LocalQueuingService.Complete is called later.
                persistedQueueStatesSnapshot = new Dictionary <IComparable, EventQueueState>();
                foreach (KeyValuePair <IComparable, EventQueueState> kv in persistedQueueStates)
                {
                    EventQueueState individualPersistedQueueStateValue = new EventQueueState();
                    individualPersistedQueueStateValue.CopyFrom(kv.Value);
                    persistedQueueStatesSnapshot.Add(kv.Key, individualPersistedQueueStateValue);
                }

                // Create backup snapshot of root queuing service's pendingQueueState
                // qService.pendingQueueState is changed when LocalQueuingService.Complete is called later.
                pendingQueueStateSnapshot = new EventQueueState();
                pendingQueueStateSnapshot.CopyFrom(pendingQueueState);

                // Reconcile differences between root and local queuing services.
                transactionalProperties.LocalQueuingService.Complete(true);
            }
        }
Exemple #3
0
 internal void PostPersist(bool isPersistSuccessful)
 {
     if (!isPersistSuccessful)
     {
         TransactionalProperties properties = this.rootWorkflowExecutor.CurrentAtomicActivity.GetValue(WorkflowExecutor.TransactionalPropertiesProperty) as TransactionalProperties;
         this.pendingQueueState    = this.pendingQueueStateSnapshot;
         this.persistedQueueStates = this.persistedQueueStatesSnapshot;
         this.rootWorkflowExecutor.RootActivity.SetValue(RootPersistedQueueStatesProperty, this.persistedQueueStatesSnapshot);
         this.rootWorkflowExecutor.RootActivity.SetValue(PendingMessagesProperty, this.pendingQueueStateSnapshot.Messages);
         properties.LocalQueuingService.SubscribeForRootMessageDelivery();
     }
     this.persistedQueueStatesSnapshot = null;
     this.pendingQueueStateSnapshot    = null;
 }
Exemple #4
0
 internal void PrePersist()
 {
     if (this.rootWorkflowExecutor.CurrentAtomicActivity != null)
     {
         TransactionalProperties properties = this.rootWorkflowExecutor.CurrentAtomicActivity.GetValue(WorkflowExecutor.TransactionalPropertiesProperty) as TransactionalProperties;
         this.persistedQueueStatesSnapshot = new Dictionary <IComparable, EventQueueState>();
         foreach (KeyValuePair <IComparable, EventQueueState> pair in this.persistedQueueStates)
         {
             EventQueueState state = new EventQueueState();
             state.CopyFrom(pair.Value);
             this.persistedQueueStatesSnapshot.Add(pair.Key, state);
         }
         this.pendingQueueStateSnapshot = new EventQueueState();
         this.pendingQueueStateSnapshot.CopyFrom(this.pendingQueueState);
         properties.LocalQueuingService.Complete(true);
     }
 }
 private void DisposeTransactionScope(TransactionalProperties transactionalProperties)
 {
     if (transactionalProperties.TransactionScope != null)
     {
         // Need to call Complete othwise the transaction will be aborted
         transactionalProperties.TransactionScope.Complete();
         transactionalProperties.TransactionScope.Dispose();
         transactionalProperties.TransactionScope = null;
         WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0,
             "Workflow Runtime: WorkflowExecutor: instanceId: " + this.InstanceIdString +
             "Left TransactionScope, Current atomic acitivity was " +
             ((this.currentAtomicActivity == null) ? null : this.currentAtomicActivity.Name));
     }
 }
        /*
         * Leaving this class in place as we will need it for the flow through tx story in V2
        class TransactionNotificationEnlistment : IEnlistmentNotification, IActivityEventListener<EventArgs>
        {
            WorkflowExecutor workflowExecutor;
            Transaction transaction;
            Activity atomicActivity;
            internal TransactionNotificationEnlistment(WorkflowExecutor exec, Transaction tx, Activity atomicActivity)
            {
                this.workflowExecutor = exec;
                this.transaction = tx;
                this.atomicActivity = atomicActivity;
            }

            #region IEnlistmentNotification Members

            void IEnlistmentNotification.Commit(Enlistment enlistment)
            {
                enlistment.Done();
            }

            void IEnlistmentNotification.InDoubt(Enlistment enlistment)
            {
                enlistment.Done();
            }

            void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
            {
                preparingEnlistment.Prepared();
            }

            void IEnlistmentNotification.Rollback(Enlistment enlistment)
            {
                //
                // Currently this method isn't used.  
                // The problem is that we must acquire the sched lock in order to schedule
                // an item.  While we wait trying to acquire the lock the transaction is held open.
                // If the instance is idle we acquire the lock right away and this works fine.
                // However is we have items to run we'll check the transaction, find that it is aborted
                // and start exception handling.  During the entire exception handling process the transaction
                // and the associated connections will be held open.  This is not good.
                // Post V1 we need scheduler changes to allow us to safely asynchronously schedule work
                // without taking the scheduler lock.
                enlistment.Done();
                //
                // ensure transaction timeout/abort is processed in case of a
                // blocked activity inside a transactional scope
                ScheduleTransactionTimeout();
            }

            private void ScheduleTransactionTimeout()
            {
                try
                {
                    //
                    // We're going to check executor state and possibly enqueue a workitem
                    // Must take the scheduleExecutor lock
                    using (this.workflowExecutor._schedulerLock.Enter())
                    {
                        if (!this.workflowExecutor.IsInstanceValid)
                            return;

                        // If the exception has already been taken care of, ignore this abort notification
                        Activity curAtomicActivity = this.workflowExecutor.currentAtomicActivity;
                        if ((curAtomicActivity != null)&&(curAtomicActivity==atomicActivity))
                        {
                            TransactionalProperties transactionalProperties = (TransactionalProperties)curAtomicActivity.GetValue(TransactionalPropertiesProperty);
                            if ((transactionalProperties.Transaction == this.transaction) &&
                                (transactionalProperties.TransactionState != TransactionProcessState.AbortProcessed))
                            {
                                transactionalProperties.TransactionState = TransactionProcessState.Aborted;

                                using (this.workflowExecutor.MessageDeliveryLock.Enter())
                                {
                                    using (new ServiceEnvironment(this.workflowExecutor.RootActivity))
                                    {
                                        using (this.workflowExecutor.SetCurrentActivity(curAtomicActivity))
                                        {
                                            //
                                            // This will schedule (async) a work item to cancel the tx scope activity
                                            // However this item will never get run - we always check if the 
                                            // tx has aborted prior to running any items so this is really 
                                            // just a "wake up" notification to the scheduler.
                                            Activity contextActivity = ContextActivityUtils.ContextActivity(curAtomicActivity);
                                            ActivityExecutorDelegateInfo<EventArgs> dummyCallback = new ActivityExecutorDelegateInfo<EventArgs>(this, contextActivity, true);
                                            dummyCallback.InvokeDelegate(contextActivity, EventArgs.Empty, false);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    WorkflowTrace.Runtime.TraceEvent(TraceEventType.Error, 0, "AbortNotificationEnlistment: instanceId: {0} failed to process ScheduleTransactionTimeout with exception {1} ", this.workflowExecutor.this.InstanceIdString, e.Message);
                }
            }

            void IActivityEventListener<EventArgs>.OnEvent(object sender, EventArgs e)
            {
                // this will never be invoked since Scheduler will process the transaction aborted request
            }

            #endregion
        }*/
        #endregion VolatileEnlistment for AbortNotification

        internal static bool CheckAndProcessTransactionAborted(TransactionalProperties transactionalProperties)
        {
            if (transactionalProperties.Transaction != null && transactionalProperties.Transaction.TransactionInformation.Status != TransactionStatus.Aborted)
                return false;

            // If transaction aborted but not processed, 
            // process it (i.e. throw to invoke Exception handling)
            // otherwise return if transaction aborted
            switch (transactionalProperties.TransactionState)
            {
                case TransactionProcessState.Ok:
                case TransactionProcessState.Aborted:
                    transactionalProperties.TransactionState = TransactionProcessState.AbortProcessed;
                    throw new TransactionAbortedException();

                case TransactionProcessState.AbortProcessed:
                    return true;

                default:
                    return false;
            }
        }
        private void CreateTransaction(Activity atomicActivity)
        {
            Debug.Assert(this.currentAtomicActivity == null, "There is already a transacted activity running");

            TransactionalProperties transactionalProperties = new TransactionalProperties();

            TransactionOptions tranOpts = new TransactionOptions();
            WorkflowTransactionOptions atomicTxn = TransactedContextFilter.GetTransactionOptions(atomicActivity);
            Debug.Assert(atomicTxn != null, "null atomicTxn");

            // 
            tranOpts.IsolationLevel = atomicTxn.IsolationLevel;
            if (tranOpts.IsolationLevel == IsolationLevel.Unspecified)
                tranOpts.IsolationLevel = IsolationLevel.Serializable;

            tranOpts.Timeout = atomicTxn.TimeoutDuration;

            // Create a promotable transaction (can be promoted to DTC when necessary)
            // as COM+ user code may want to participate in the transaction
            // Enlist to the transaction for abort notification
            System.Transactions.CommittableTransaction transaction = new CommittableTransaction(tranOpts);
            // Can switch back to using TransactionCompletionHandler once VS562627 is fixed
            // transaction.TransactionCompleted += new TransactionCompletedEventHandler(TransactionCompletionHandler);
            //transaction.EnlistVolatile(new TransactionNotificationEnlistment(this, transaction, atomicActivity), EnlistmentOptions.None);
            transactionalProperties.Transaction = transaction;
            WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0,
                "Workflow Runtime: WorkflowExecutor: instanceId: " + this.InstanceIdString +
                " .Created enlistable transaction " + ((System.Transactions.Transaction)transaction).GetHashCode() +
                " with timeout " + tranOpts.Timeout + ", isolation " + tranOpts.IsolationLevel);

            // create a local queuing service per atomic context
            transactionalProperties.LocalQueuingService = new WorkflowQueuingService(this.qService);

            // Store the transaction properties onto the activity
            atomicActivity.SetValue(TransactionalPropertiesProperty, transactionalProperties);

            // Set current atomic activity
            this.currentAtomicActivity = atomicActivity;
            atomicActivityEvent = new ManualResetEvent(false);
            WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "Workflow Runtime: WorkflowExecutor: instanceId: " + this.InstanceIdString + " .Set CurrentAtomicActivity to " + atomicActivity.Name);
        }
Exemple #8
0
        public void Run()
        {
            do
            {
                this.RootWorkflowExecutor.ProcessQueuedEvents();
                // Get item to run
                SchedulableItem item        = GetItemToRun();
                bool            runningItem = false;

                // no ready work to run... go away
                if (item == null)
                {
                    break;
                }

                Activity  itemActivity = null;
                Exception exp          = null;

                TransactionalProperties transactionalProperties = null;
                int contextId = item.ContextId;

                // This function gets the root or enclosing while-loop activity
                Activity contextActivity = this.RootWorkflowExecutor.GetContextActivityForId(contextId);
                if (contextActivity == null)
                {
                    throw new InvalidOperationException(ExecutionStringManager.InvalidExecutionContext);
                }

                // This is the activity corresponding to the item's ActivityId
                itemActivity = contextActivity.GetActivityByName(item.ActivityId);
                using (new ServiceEnvironment(itemActivity))
                {
                    exp = null;
                    bool ignoreFinallyBlock = false;

                    try
                    {
                        // item preamble
                        // set up the item transactional context if necessary
                        //
                        Debug.Assert(itemActivity != null, "null itemActivity");
                        if (itemActivity == null)
                        {
                            throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.InvalidActivityName, item.ActivityId));
                        }

                        Activity atomicActivity = null;
                        if (this.RootWorkflowExecutor.IsActivityInAtomicContext(itemActivity, out atomicActivity))
                        {
                            transactionalProperties = (TransactionalProperties)atomicActivity.GetValue(WorkflowExecutor.TransactionalPropertiesProperty);
                            // If we've aborted for any reason stop now!
                            // If we attempt to enter a new TransactionScope the com+ context will get corrupted
                            // See windows se bug 137267
                            if (!WorkflowExecutor.CheckAndProcessTransactionAborted(transactionalProperties))
                            {
                                if (transactionalProperties.TransactionScope == null)
                                {
                                    // Use TimeSpan.Zero so scope will not create timeout independent of the transaction
                                    // Use EnterpriseServicesInteropOption.Full to flow transaction to COM+
                                    transactionalProperties.TransactionScope =
                                        new TransactionScope(transactionalProperties.Transaction, TimeSpan.Zero, EnterpriseServicesInteropOption.Full);

                                    WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0,
                                                                     "Workflow Runtime: Scheduler: instanceId: " + this.RootWorkflowExecutor.InstanceIdString +
                                                                     "Entered into TransactionScope, Current atomic acitivity " + atomicActivity.Name);
                                }
                            }
                        }

                        // Run the item
                        //
                        runningItem = true;
                        WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 1, "Workflow Runtime: Scheduler: InstanceId: {0} : Running scheduled entry: {1}", this.RootWorkflowExecutor.InstanceIdString, item.ToString());

                        // running any entry implicitly changes some state of the workflow instance
                        this.RootWorkflowExecutor.stateChangedSincePersistence = true;

                        item.Run(this.RootWorkflowExecutor);
                    }
                    catch (Exception e)
                    {
                        if (WorkflowExecutor.IsIrrecoverableException(e))
                        {
                            ignoreFinallyBlock = true;
                            throw;
                        }
                        else
                        {
                            if (transactionalProperties != null)
                            {
                                transactionalProperties.TransactionState = TransactionProcessState.AbortProcessed;
                            }
                            exp = e;
                        }
                    }
                    finally
                    {
                        if (!ignoreFinallyBlock)
                        {
                            if (runningItem)
                            {
                                WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 1, "Workflow Runtime: Scheduler: InstanceId: {0} : Done with running scheduled entry: {1}", this.RootWorkflowExecutor.InstanceIdString, item.ToString());
                            }

                            // Process exception
                            //
                            if (exp != null)
                            {
                                //
                                this.RootWorkflowExecutor.ExceptionOccured(exp, itemActivity == null ? contextActivity : itemActivity, null);
                                exp = null;
                            }
                        }
                    }
                }
            } while (true);
        }
 private void CreateTransaction(Activity atomicActivity)
 {
     TransactionalProperties properties = new TransactionalProperties();
     TransactionOptions options = new TransactionOptions();
     WorkflowTransactionOptions transactionOptions = TransactedContextFilter.GetTransactionOptions(atomicActivity);
     options.IsolationLevel = transactionOptions.IsolationLevel;
     if (options.IsolationLevel == IsolationLevel.Unspecified)
     {
         options.IsolationLevel = IsolationLevel.Serializable;
     }
     options.Timeout = transactionOptions.TimeoutDuration;
     CommittableTransaction transaction = new CommittableTransaction(options);
     properties.Transaction = transaction;
     WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, string.Concat(new object[] { "Workflow Runtime: WorkflowExecutor: instanceId: ", this.InstanceIdString, " .Created enlistable transaction ", transaction.GetHashCode(), " with timeout ", options.Timeout, ", isolation ", options.IsolationLevel }));
     properties.LocalQueuingService = new WorkflowQueuingService(this.qService);
     atomicActivity.SetValue(TransactionalPropertiesProperty, properties);
     this.currentAtomicActivity = atomicActivity;
     this.atomicActivityEvent = new ManualResetEvent(false);
     WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "Workflow Runtime: WorkflowExecutor: instanceId: " + this.InstanceIdString + " .Set CurrentAtomicActivity to " + atomicActivity.Name);
 }
        internal static bool CheckAndProcessTransactionAborted(TransactionalProperties transactionalProperties)
        {
            if ((transactionalProperties.Transaction == null) || (transactionalProperties.Transaction.TransactionInformation.Status == TransactionStatus.Aborted))
            {
                switch (transactionalProperties.TransactionState)
                {
                    case TransactionProcessState.Ok:
                    case TransactionProcessState.Aborted:
                        transactionalProperties.TransactionState = TransactionProcessState.AbortProcessed;
                        throw new TransactionAbortedException();

                    case TransactionProcessState.AbortProcessed:
                        return true;
                }
            }
            return false;
        }
        public void CheckpointInstanceState(Activity atomicActivity)
        {
            // Note that the WF4 runtime does not create checkpoints.  If the transaction aborts, the workflow aborts.  
            // We are following the WF4 behavior and not creating a checkpoint.

            TransactionOptions tranOpts = new TransactionOptions();
            WorkflowTransactionOptions atomicTxn = TransactedContextFilter.GetTransactionOptions(atomicActivity);

            tranOpts.IsolationLevel = atomicTxn.IsolationLevel;
            if (tranOpts.IsolationLevel == IsolationLevel.Unspecified)
            {
                tranOpts.IsolationLevel = IsolationLevel.Serializable;
            }

            tranOpts.Timeout = atomicTxn.TimeoutDuration;

            TransactionalProperties transactionProperties = new TransactionalProperties();
            atomicActivity.SetValue(WorkflowExecutor.TransactionalPropertiesProperty, transactionProperties);
            this.ServiceProvider.CreateTransaction(tranOpts);
            this.currentAtomicActivity = atomicActivity;
            this.scheduler.Pause();
        }
        public bool CheckAndProcessTransactionAborted(TransactionalProperties transactionalProperties)
        {
            if (transactionalProperties.Transaction != null && transactionalProperties.Transaction.TransactionInformation.Status != TransactionStatus.Aborted)
            {
                return false;
            }

            if (transactionalProperties.TransactionState != TransactionProcessState.AbortProcessed)
            {
                // The transaction has aborted.  The WF3 runtime throws a TransactionAborted exception here, which then propagates as fault.
                // But WF4 aborts the workflow, so pause the scheduler and return.
                this.scheduler.Pause();
                transactionalProperties.TransactionState = TransactionProcessState.AbortProcessed;
            }

            return true;
        }
        public void Run()
        {
Label_0000:
            this.RootWorkflowExecutor.ProcessQueuedEvents();
            SchedulableItem itemToRun = this.GetItemToRun();
            bool            flag      = false;

            if (itemToRun != null)
            {
                Activity  currentActivity = null;
                Exception exp             = null;
                TransactionalProperties transactionalProperties = null;
                int      contextId            = itemToRun.ContextId;
                Activity contextActivityForId = this.RootWorkflowExecutor.GetContextActivityForId(contextId);
                if (contextActivityForId == null)
                {
                    throw new InvalidOperationException(ExecutionStringManager.InvalidExecutionContext);
                }
                currentActivity = contextActivityForId.GetActivityByName(itemToRun.ActivityId);
                using (new ServiceEnvironment(currentActivity))
                {
                    exp = null;
                    bool flag2 = false;
                    try
                    {
                        if (currentActivity == null)
                        {
                            throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ExecutionStringManager.InvalidActivityName, new object[] { itemToRun.ActivityId }));
                        }
                        Activity atomicActivity = null;
                        if (this.RootWorkflowExecutor.IsActivityInAtomicContext(currentActivity, out atomicActivity))
                        {
                            transactionalProperties = (TransactionalProperties)atomicActivity.GetValue(WorkflowExecutor.TransactionalPropertiesProperty);
                            if (!WorkflowExecutor.CheckAndProcessTransactionAborted(transactionalProperties) && (transactionalProperties.TransactionScope == null))
                            {
                                transactionalProperties.TransactionScope = new TransactionScope(transactionalProperties.Transaction, TimeSpan.Zero, EnterpriseServicesInteropOption.Full);
                                WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "Workflow Runtime: Scheduler: instanceId: " + this.RootWorkflowExecutor.InstanceIdString + "Entered into TransactionScope, Current atomic acitivity " + atomicActivity.Name);
                            }
                        }
                        flag = true;
                        WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 1, "Workflow Runtime: Scheduler: InstanceId: {0} : Running scheduled entry: {1}", new object[] { this.RootWorkflowExecutor.InstanceIdString, itemToRun.ToString() });
                        this.RootWorkflowExecutor.stateChangedSincePersistence = true;
                        itemToRun.Run(this.RootWorkflowExecutor);
                    }
                    catch (Exception exception2)
                    {
                        if (WorkflowExecutor.IsIrrecoverableException(exception2))
                        {
                            flag2 = true;
                            throw;
                        }
                        if (transactionalProperties != null)
                        {
                            transactionalProperties.TransactionState = TransactionProcessState.AbortProcessed;
                        }
                        exp = exception2;
                    }
                    finally
                    {
                        if (!flag2)
                        {
                            if (flag)
                            {
                                WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 1, "Workflow Runtime: Scheduler: InstanceId: {0} : Done with running scheduled entry: {1}", new object[] { this.RootWorkflowExecutor.InstanceIdString, itemToRun.ToString() });
                            }
                            if (exp != null)
                            {
                                this.RootWorkflowExecutor.ExceptionOccured(exp, (currentActivity == null) ? contextActivityForId : currentActivity, null);
                                exp = null;
                            }
                        }
                    }
                    goto Label_0000;
                }
            }
        }