예제 #1
0
        // call from the threadProvider about the availability of a thread.
        internal void RunSome(object ignored)
        {
            using (ScheduleWork work = new ScheduleWork(this))
            {
                using (new WorkflowTraceTransfer(this.InstanceId))
                {
                    using (new SchedulerLockGuard(this._schedulerLock, this))
                    {
                        using (new ServiceEnvironment(this.rootActivity))
                        {
                            // check if this is a valid in-memory instance
                            if (!this.IsInstanceValid)
                                return;

                            // check if instance already done
                            if ((this.rootActivity.ExecutionStatus == ActivityExecutionStatus.Closed) || (WorkflowStatus.Completed == this.WorkflowStatus) || (WorkflowStatus.Terminated == this.WorkflowStatus))
                                return;

                            bool ignoreFinallyBlock = false;

                            //
                            // For V1 we don't support flow through transaction on the service thread
                            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress))
                            {
                                try
                                {
                                    FireWorkflowExecutionEvent(this, WorkflowEventInternal.Executing);
                                    // run away ... run away...
                                    this.RunScheduler();
                                }
                                catch (Exception e)
                                {
                                    if (WorkflowExecutor.IsIrrecoverableException(e))
                                    {
                                        ignoreFinallyBlock = true;
                                        throw;
                                    }
                                    else
                                    {
                                        WorkflowTrace.Runtime.TraceEvent(TraceEventType.Error, 0, "Workflow Runtime: WorkflowExecutor: Fatal exception thrown in the scheduler. Terminating the workflow instance '{0}'. Exception:{1}\n{2}", this.InstanceIdString, e.Message, e.StackTrace);
                                        this.TerminateOnIdle(WorkflowExecutor.GetNestedExceptionMessage(e));
                                        this.ThrownException = e;
                                    }
                                }
                                finally
                                {
                                    if (!ignoreFinallyBlock)
                                    {
                                        FireWorkflowExecutionEvent(this, WorkflowEventInternal.NotExecuting);
                                    }
                                }
                                scope.Complete();
                            }
                        }
                    }
                }
            }
        }
예제 #2
0
        internal void Start()
        {
            using (ScheduleWork work = new ScheduleWork(this))
            {
                using (this.ExecutorLock.Enter())
                {
                    if (this.WorkflowStatus != WorkflowStatus.Created)
                        throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.CannotStartInstanceTwice, this.InstanceId));

                    // Set a new ServiceEnvironment to establish a current batch in TLS
                    // This is needed for synchronous status change notification at start
                    // (status init->executing) when there is no batch in TLS yet
                    // and there are subscribers like tracking
                    this.WorkflowStatus = WorkflowStatus.Running;
                    using (new ServiceEnvironment(this.rootActivity))
                    {
                        FireWorkflowExecutionEvent(this, WorkflowEventInternal.Starting);
                        try
                        {
                            using (ActivityExecutionContext executionContext = new ActivityExecutionContext(this.rootActivity, true))
                            {
                                // make sure the scheduler is able to run
                                this.schedulingContext.CanRun = true;

                                // Since we are actually scheduling work at this point, we should grab
                                // the scheduler lock. This will avoid ----s some operations we schedule
                                // start executing before we are done scheduling all operations.
                                using (new SchedulerLockGuard(this._schedulerLock, this))
                                {
                                    executionContext.ExecuteActivity(this.rootActivity);
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            Terminate(e.Message);
                            throw;
                        }
                        FireWorkflowExecutionEvent(this, WorkflowEventInternal.Started);

                    }
                }
            }
        }
예제 #3
0
        internal void DeliverTimerSubscriptions()
        {
            using (ScheduleWork work = new ScheduleWork(this))
            {
                using (this._executorLock.Enter())
                {
                    if (this.IsInstanceValid)
                    {
                        using (this.MessageDeliveryLock.Enter())
                        {
                            using (new ServiceEnvironment(this.rootActivity))
                            {
                                if (!this.IsInstanceValid)
                                    return;

                                TimerEventSubscriptionCollection queue = TimerQueue;
                                bool done = false;
                                while (!done)
                                {
                                    lock (queue.SyncRoot)
                                    {
                                        TimerEventSubscription sub = queue.Peek();
                                        if (sub == null || sub.ExpiresAt > DateTime.UtcNow)
                                        {
                                            done = true;
                                        }
                                        else
                                        {
                                            WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "Delivering timer subscription for instance {0}", this.InstanceIdString);
                                            stateChangedSincePersistence = true;
                                            lock (qService.SyncRoot)
                                            {
                                                if (qService.Exists(sub.QueueName))
                                                {
                                                    qService.EnqueueEvent(sub.QueueName, sub.SubscriptionId);
                                                }
                                            }
                                            queue.Dequeue();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #4
0
 internal void Registered(bool isActivation)
 {
     using (ScheduleWork work = new ScheduleWork(this))
     {
         this.Scheduler.ResumeIfRunnable();
     }
     if (isActivation)
         FireWorkflowExecutionEvent(this, WorkflowEventInternal.Created);
     else
         FireWorkflowExecutionEvent(this, WorkflowEventInternal.Loaded);
 }
예제 #5
0
        internal void ApplyWorkflowChanges(WorkflowChanges workflowChanges)
        {
            // Accessing InstanceId is not thread safe here!
            //WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "Workflow Runtime: WorkflowExecutor: Got a dynamic update request from outside for instance {0}", this.InstanceIdString);
            DiagnosticStackTrace("dynamic update request");

            // check arguments
            if (workflowChanges == null)
                throw new ArgumentNullException("workflowChanges");

            // check if this is a valid in-memory instance
            if (!this.IsInstanceValid)
                throw new InvalidOperationException(ExecutionStringManager.WorkflowNotValid);

            if (this.currentAtomicActivity != null)
                throw new InvalidOperationException(ExecutionStringManager.Error_InsideAtomicScope);

            try
            {
                using (ScheduleWork work = new ScheduleWork(this))
                {
                    // block other instance operations from outside
                    using (this._executorLock.Enter())
                    {
                        // check if this is a valid in-memory instance
                        if (!this.IsInstanceValid)
                            throw new InvalidOperationException(ExecutionStringManager.WorkflowNotValid);

                        // get the instance to stop running
                        this.Scheduler.CanRun = false;
                        using (new SchedulerLockGuard(this._schedulerLock, this))
                        {
                            using (new ServiceEnvironment(this.rootActivity))
                            {
                                bool localSuspend = false;

                                // check if this is a valid in-memory instance
                                if (!this.IsInstanceValid)
                                    throw new InvalidOperationException(ExecutionStringManager.WorkflowNotValid);

                                try
                                {
                                    // check the status of the schedule
                                    switch (this.WorkflowStatus)
                                    {
                                        ////case ActivityExecutionStatus.Completed:
                                        // 
                                        case WorkflowStatus.Completed:
                                        case WorkflowStatus.Terminated:
                                            throw new InvalidOperationException(
                                                ExecutionStringManager.InvalidOperationRequest);
                                        case WorkflowStatus.Suspended:
                                            // instance already suspended
                                            localSuspend = false;
                                            break;
                                        default:
                                            // suspend the instance
                                            this.SuspendOnIdle(null);
                                            localSuspend = true;
                                            break;
                                    }

                                    // apply the changes
                                    workflowChanges.ApplyTo(this.rootActivity);
                                }
                                finally
                                {
                                    if (localSuspend)
                                    {
                                        // @undone: for now this will not return till the instance is done
                                        // Once Kumar has fixed 4335, we can enable this.
                                        this.ResumeOnIdle(true);
                                    }
                                }
                            }
                        } // release lock on scheduler
                    }
                }
            }
            catch (Exception e)
            {
                WorkflowTrace.Runtime.TraceEvent(TraceEventType.Error, 0, "Workflow Runtime: WorkflowExecutor: dynamic update attempt from outside on instance '{0}' threw an exception '{1}' at {2}", this.InstanceIdString, e.Message, e.StackTrace);
                throw;
            }
        }
예제 #6
0
        // resumes the schedule instance sync
        // must be called only from outside the instance... the thread running the instance must
        // never call this method... it should call ResumeOnIdle instead.
        internal void Resume()
        {
            WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "Workflow Runtime: WorkflowExecutor: Got a resume request for instance {0}", this.InstanceIdString);

            try
            {
                // check if this is a valid in-memory instance
                if (!this.IsInstanceValid)
                    throw new InvalidOperationException(ExecutionStringManager.WorkflowNotValid);

                using (ScheduleWork work = new ScheduleWork(this))
                {
                    // Stop threads from outside - message delivery and control operations
                    using (this._executorLock.Enter())
                    {
                        // check if this is a valid in-memory instance
                        if (!this.IsInstanceValid)
                            throw new InvalidOperationException(ExecutionStringManager.WorkflowNotValid);

                        if ((this.WorkflowStatus != WorkflowStatus.Suspended))
                            return;

                        using (new SchedulerLockGuard(this._schedulerLock, this))
                        {
                            //@@Undone-- bmalhi there is one test in bat
                            //which fails here. This check is right thing but im 
                            //commenting it out for bat.
                            // Microsoft:  this fails because when we load an instance into memory it grabs
                            // the scheduler lock and starts running.  By the time the user Resume request
                            // gets the scheduler lock the instance is often done (the AbortBat test case scenario)
                            // Balinder is attempting a fix to separate rehydration from resuming execution.
                            /*if (!this.IsInstanceValid)
                                throw new InvalidOperationException(ExecutionStringManager.WorkflowNotValid);
                             */
                            using (new ServiceEnvironment(this.rootActivity))
                            {
                                this.ResumeOnIdle(true);
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                WorkflowTrace.Runtime.TraceEvent(TraceEventType.Error, 0, "Workflow Runtime: WorkflowExecutor: Resume attempt on instance '{0}' threw an exception '{1}' at {2}", this.InstanceIdString, e.Message, e.StackTrace);
                throw;
            }
        }
예제 #7
0
        internal void EnqueueItemOnIdle(IComparable queueName, object item, IPendingWork pendingWork, Object workItem)
        {
            using (ScheduleWork work = new ScheduleWork(this))
            {
                // prevent other control operations from outside
                using (this._executorLock.Enter())
                {
                    if (!this.IsInstanceValid)
                        throw new InvalidOperationException(ExecutionStringManager.WorkflowNotValid);

                    // take the msg delivery lock to make sure the instance
                    // doesn't persist while the message is being delivered.
                    using (InstanceLock.InstanceLockGuard messageDeliveryLockGuard = this.MessageDeliveryLock.Enter())
                    {
                        using (new ServiceEnvironment(this.rootActivity))
                        {

                            if (!this.IsInstanceValid)
                                throw new InvalidOperationException(ExecutionStringManager.WorkflowNotValid);

                            // Wait until the Scheduler is idle.
                            while (!this.IsIdle)
                            {
                                messageDeliveryLockGuard.Wait();
                                if (!this.IsInstanceValid)
                                    throw new InvalidOperationException(ExecutionStringManager.WorkflowNotValid);
                            }

                            // At this point the scheduler is not running and it is 
                            // EnqueueItemOnIdle is not valid for suspended workflows
                            if ((this.WorkflowStatus == WorkflowStatus.Suspended) || (!this.Scheduler.CanRun))
                                throw new InvalidOperationException(ExecutionStringManager.InvalidWaitForIdleOnSuspendedWorkflow);

                            try
                            {
                                // add work items to the current batch if exists
                                if (pendingWork != null)
                                {
                                    IWorkBatch batch = (IWorkBatch)this.rootActivity.GetValue(WorkflowExecutor.TransientBatchProperty);
                                    batch.Add(pendingWork, workItem);
                                }

                                stateChangedSincePersistence = true;
                                qService.EnqueueEvent(queueName, item);
                            }
                            finally
                            {
                                if (this.IsIdle)
                                    messageDeliveryLockGuard.Pulse();
                            }
                        }
                    }
                }
            }
        }
예제 #8
0
        internal void EnqueueItem(IComparable queueName, object item, IPendingWork pendingWork, Object workItem)
        {
            using (ScheduleWork work = new ScheduleWork(this))
            {
                bool lockedScheduler = false;
                if (!ServiceEnvironment.IsInServiceThread(InstanceId))
                    lockedScheduler = _schedulerLock.TryEnter();
                try
                {
                    // take the msg delivery lock to make sure the instance
                    // doesn't persist while the message is being delivered.
                    using (this.MessageDeliveryLock.Enter())
                    {
                        if (!this.IsInstanceValid)
                            throw new InvalidOperationException(ExecutionStringManager.WorkflowNotValid);

                        if (lockedScheduler || ServiceEnvironment.IsInServiceThread(InstanceId))
                        {
                            using (new ServiceEnvironment(this.RootActivity))
                            {
                                qService.EnqueueEvent(queueName, item);
                            }
                        }
                        else
                        {
                            if (qService.SafeEnqueueEvent(queueName, item))
                            {
                                ScheduleWork.NeedsService = true;
                            }
                        }

                        // add work items to the current batch if exists
                        if (pendingWork != null)
                        {
                            IWorkBatch batch = _resourceManager.BatchCollection.GetBatch(this.rootActivity);
                            batch.Add(pendingWork, workItem);
                        }

                        stateChangedSincePersistence = true;
                    }
                }
                finally
                {
                    if (lockedScheduler)
                        _schedulerLock.Exit();
                }
            }
        }