public override bool OnResume(IRunState context, IWorkflowEvent resumeEvent)
        {
            if (resumeEvent is NotifyResumeFailedEvent)
            {
                throw new WorkflowRunException("Workflow failed with an internal error.");
            }

            var notification = context.GetArgValue <IEntity>(ActivityInstance, GetArgumentKey("core:outNotificationRecord"));

            if (notification == null)
            {
                throw new ArgumentException("notification");
            }

            var writable = notification.AsWritable <Notification>();

            if (writable.NPendingRun != null)
            {
                writable.NPendingRun = null;
                writable.Save();
            }

            HandleTimeout(context, resumeEvent);

            return(true);       // keep going
        }
Example #2
0
        public string ResumeWorkflowAsync_new(WorkflowRun workflowRun, IWorkflowEvent resumeEvent)
        {
            Factory.WorkflowRunTaskManager.RegisterStart(workflowRun.TaskId);

            bool runInForeground = WorkflowRunContext.Current.RunTriggersInCurrentThread;

            var queueEvent = resumeEvent as IWorkflowQueuedEvent;

            if (queueEvent == null)
            {
                EventLog.Application.WriteError("Attempted to queue a resume task that cannot be queued, running it on the foreground thread instead. EventType: {resumeEvent.GetType()}");
                runInForeground = true;
            }

            if (runInForeground)
            {
                ResumeWorkflow(workflowRun, resumeEvent);
            }
            else
            {
                var task = ResumeWorkflowHandler.CreateBackgroundTask(workflowRun, queueEvent);

                Factory.BackgroundTaskManager.EnqueueTask(task);

                HandleDiagnostics(workflowRun, "Queued");
            }

            return(workflowRun.TaskId);
        }
Example #3
0
        private string ResumeWorkflowAsync_old(WorkflowRun workflowRun, IWorkflowEvent resumeEvent)
        {
            Action runAction = () =>
            {
                using (new WorkflowRunContext {
                    RunTriggersInCurrentThread = true
                })
                {
                    ResumeWorkflow(workflowRun, resumeEvent);
                }
            };

            Factory.WorkflowRunTaskManager.RegisterStart(workflowRun.TaskId);
            HandleDiagnostics(workflowRun, "Queued");

            if (WorkflowRunContext.Current.RunTriggersInCurrentThread)
            {
                // Ignore the Asyn and process it syncronously
                runAction();
            }
            else // Async
            {
                WorkflowRunContext.Current.QueueAction(() =>
                {
                    runAction();
                });
            }

            return(workflowRun.TaskId);
        }
        /// <summary>
        /// Continue a paused activity
        /// </summary>
        /// <returns>True if the activity has completed, false if it is paused.</returns>
        public override bool OnResume(IRunState context, IWorkflowEvent resumeEvent)
        {
            var userCompletesEvent = resumeEvent as PromptUserTaskCompletedEvent;

            if (userCompletesEvent != null)
            {
                context.ExitPointId = new EntityRef("promptUserCompleted");

                var userTaskId = userCompletesEvent.UserTaskId;

                var userTask = Entity.Get <PromptUserTask>(userTaskId, PromptUserTask.PromptForTaskStateInfo_Field);
                if (userTask != null)
                {
                    // load the state information in the task back into the workflow run context
                    foreach (var arg in userTask.PromptForTaskArguments)
                    {
                        var input = userTask.PromptForTaskStateInfo.FirstOrDefault(si => si.StateInfoArgument.Id == arg.ActivityPromptArgument.Id);
                        if (input == null)
                        {
                            continue;
                        }

                        context.SetArgValue(input.StateInfoArgument, ActivityArgumentHelper.GetArgParameterValue(input.StateInfoValue));
                    }

                    Entity.Delete(userTask);
                }
            }

            return(true);
        }
        /// <summary>
        /// Cancel a timeout if one has been set. If a timeout has occured set the exit point to the timeout exit
        /// </summary>
        /// <param name="context"></param>
        /// <returns>true is a time-out has occured</returns>
        protected bool HandleTimeout(IRunState context, IWorkflowEvent resumeEvent)
        {
            if (context.HasTimeout)
            {
                TimeoutActivityHelper.Instance.CancelTimeout(context.WorkflowRun);
                context.HasTimeout = false;
            }

            var timeoutEvent = resumeEvent as TimeoutEvent;

            if (timeoutEvent != null)
            {
                var timeoutTrans = GetTimeoutTransition();

                if (timeoutTrans == null)
                {
                    throw new ApplicationException("There should never be a time-out without a time-out exit point.");
                }

                context.ExitPointId = timeoutTrans.FromExitPoint;

                return(true);
            }
            else
            {
                return(false);
            }
        }
        bool IResumableActivity.OnResume(IRunState context, IWorkflowEvent resumeEvent)
        {
            var run = ((ChildWorkflowCompletedEvent)resumeEvent).CompletedRun;

            ProcessResult(context, run);

            return(true);
        }
Example #7
0
        /// <summary>
        /// Run the next step in the workflow by scheduling the activity. This call in turn will schedule other activities.
        /// </summary>
        private void ScheduleResumeStep(IRunState context, IWorkflowEvent resumeEvent, WfActivity childActivity)
        {
            // set the input
            var windowsActivity = (ActivityImplementationBase)context.Metadata.CachedInstances[childActivity.Id];
            var resumable       = (IResumableActivity)windowsActivity;

            context.WorkflowInvoker.ScheduleResume(context, windowsActivity, resumeEvent, NextStepCompletionCallback, NextStepPausedCallback);
        }
Example #8
0
        /// <summary>
        /// Raise an event. Events are handled in the order raised after the other processing has completed
        /// </summary>
        /// <param name="nextEvent"></param>
        public void PostEvent(IWorkflowEvent nextEvent)
        {
            Action action = null;

            var asChildRunStart = nextEvent as ChildWorkflowStartEvent;

            if (asChildRunStart != null)
            {
                var parentRun = asChildRunStart.ParentRun;
                if (parentRun != null)
                {
                    var triggerDepth = WorkflowRunContext.Current.TriggerDepth;
                    action = () => {
                        // Need to handle deferred here otherwise "double-resume" fails (BUG #27863)
                        using (new WorkflowRunContext(true)
                        {
                            TriggerDepth = triggerDepth + 1
                        })
                        {
                            var startEvent = new WorkflowStartEvent(asChildRunStart.WorkflowToStart)
                            {
                                Arguments = asChildRunStart.Inputs,
                                ParentRun = parentRun,
                                Trace     = parentRun.RunTrace ?? false
                            };

                            // TODO: Change this into a call into the BackgroundTaskManager
                            WorkflowRunner.Instance.RunWorkflow(startEvent);
                        }
                    };
                }
            }
            else
            {
                var asChildRunCompleted = nextEvent as ChildWorkflowCompletedEvent;

                if (asChildRunCompleted != null)
                {
                    var completedRun = asChildRunCompleted.CompletedRun;
                    if (completedRun != null)
                    {
                        // Need to decrement the trigger depth otherwise "child workflow in a foreach" fails (BUG #27863)
                        if (WorkflowRunContext.Current.TriggerDepth > 0)
                        {
                            WorkflowRunContext.Current.TriggerDepth--;
                        }
                        action = () => WorkflowRunner.Instance.ResumeWorkflow(completedRun.ParentRun, asChildRunCompleted);
                    }
                }
            }

            if (action != null)
            {
                // NOTE: runBeforeSave was passed as "true" here, however, this led to issues where previously
                // unsaved copies of the same run were already present in the queue, causing endless looping (BUG #27863)
                WorkflowRunContext.Current.DeferAction(action, false);
            }
        }
Example #9
0
 /// <summary>
 /// Resume a workflow. The workflow will run async unless it is in a RunTriggersInCurrentThread WorkflowContext.
 /// </summary>
 /// <param name="workflowRun"></param>
 /// <param name="resumeEvent"></param>
 public string ResumeWorkflowAsync(WorkflowRun workflowRun, IWorkflowEvent resumeEvent)
 {
     if (Factory.FeatureSwitch.Get("longRunningWorkflow"))
     {
         return(ResumeWorkflowAsync_new(workflowRun, resumeEvent));
     }
     else
     {
         return(ResumeWorkflowAsync_old(workflowRun, resumeEvent));
     }
 }
Example #10
0
 public void HandleEvent(IWorkflowEvent workflowEvent)
 {
     foreach (var rule in TransitionRules)
     {
         var nextState = rule.Transition(workflowEvent, this, _state);
         if (nextState != null)
         {
             _currentState = nextState;
         }
     }
 }
        public override bool OnResume(IRunState context, IWorkflowEvent resumeEvent)
        {
            if (!HandleTimeout(context, resumeEvent))      // handle timeout will set the exit point
            {
                HandleResumeTransition(context, (IWorkflowUserTransitionEvent)resumeEvent);

                //if (!(userTask.HideComment ?? false))
                //    context.SetArgValue(ActivityInstance, GetArgumentKey("core:outTaskComment"), userTask.TaskComment);
            }

            return(true);
        }
        /// <summary>
        /// Responds to a paused activity being resumed.
        /// </summary>
        /// <param name="context">The current running context of the workflow.</param>
        /// <param name="resumeEvent">Information about the event that caused the resumption of the activity.</param>
        /// <returns>True if the activity has completed, false if it is paused.</returns>
        public bool OnResume(IRunState context, IWorkflowEvent resumeEvent)
        {
            TRequest  request  = null;
            TResponse response = null;

            using (Profiler.Measure("CastActivityImplementation.OnResume"))
            {
                try
                {
                    if (resumeEvent is ICastActivityResponseEvent)
                    {
                        LogToRun(context, string.Format("CAST Activity '{0}' is resuming.", ActivityInstance.Name));

                        var castEvent = resumeEvent as CastActivityResponseEvent <TRequest, TResponse>;
                        if (castEvent != null)
                        {
                            request  = castEvent.Request;
                            response = castEvent.Response;
                        }

                        if (response != null && response.IsError)
                        {
                            throw new WorkflowRunException("CAST Activity failed at the remote end. ({0})", response.Error);
                        }

                        OnResponse(context, request, response);
                    }
                }
                catch (Exception e)
                {
                    EventLog.Application.WriteError("An unexpected error occurred when resuming a CAST activity. {0}", e.ToString());

                    LogToRun(context, string.Format("CAST Activity '{0}' failed to resume.", ActivityInstance.Name));

                    if (string.IsNullOrEmpty(FailureExitPointAlias))
                    {
                        throw;
                    }

                    context.ExitPointId = new EntityRef(FailureExitPointAlias);
                }
            }

            return(true);
        }
Example #13
0
        /// <summary>
        /// Run activity using its own context. The activity can not have any pending actions when it completes)
        /// </summary>
        /// <returns>True if the run completed.</returns>
        bool ProcessWorkflow(Workflow wf, IRunState runState, IWorkflowEvent wfEvent)
        {
            var activityInst = wf.Cast <WfActivity>();
            var activityImp  = activityInst.CreateWindowsActivity();

            var metadata = runState.Metadata;
            var invoker  = runState.WorkflowInvoker;

            if (!metadata.HasViolations)
            {
                var startEvent = wfEvent as WorkflowStartEvent;

                if (startEvent != null)
                {
                    var inputArgs = activityInst.GetInputArguments();
                    var inputs    = new ActivityInputs(inputArgs, startEvent.Arguments);

                    invoker.ScheduleActivity(runState, activityImp, inputs, null, null);
                }
                else
                {
                    invoker.ScheduleResume(runState, activityImp, wfEvent, null, null);
                }

                try
                {
                    var result = RunTillCompletion(invoker, runState);
                    return(result);
                }
                catch (PlatformSecurityException ex)
                {
                    throw new WorkflowRunException(ex.Message, ex);
                }
                catch (WorkflowRunException_Internal ex)
                {
                    throw new WorkflowRunException(ex.Message, ex.InnerException);
                }
            }

            var act = GetActivityForError(runState, activityInst);

            throw new WorkflowValidationException(runState.WorkflowRunId, act.ContainingWorkflow, act, metadata.ValidationMessages);
        }
        public override bool OnResume(IRunState context, IWorkflowEvent resumeEvent)
        {
            var userTaskEntity = context.GetArgValue <IEntity>(ActivityInstance, GetArgumentKey("core:outDisplayFormUserTask"));
            var keepHistory    = context.GetArgValue <bool>(ActivityInstance, GetArgumentKey("core:dfaInternalKeepHistory"));

            var userTask = userTaskEntity != null?userTaskEntity.As <DisplayFormUserTask>() : null;         // We could have a combination of a deleted user task and a time-out


            if (!HandleTimeout(context, resumeEvent))       // handle timeout will set the exit point
            {
                HandleResumeTransition(context, (IWorkflowUserTransitionEvent)resumeEvent);

                if (!(userTask.HideComment ?? false))
                {
                    context.SetArgValue(ActivityInstance, GetArgumentKey("core:outTaskComment"), userTask.TaskComment);
                }

                if (keepHistory)
                {
                    var writableTask = userTask.AsWritable <DisplayFormUserTask>();
                    writableTask.TaskStatus_Enum = TaskStatusEnum_Enumeration.TaskStatusCompleted;
                    writableTask.Save();
                }
            }

            if (userTask != null)
            {
                if (keepHistory)
                {
                    if (userTask.LogEntryForUserAction != null)
                    {
                        UpdateLogEntry(userTask);
                    }
                }
                else
                {
                    context.SetArgValue(ActivityInstance, GetArgumentKey("core:outDisplayFormUserTask"), null);
                    Entity.Delete(userTask);
                }
            }

            return(true);
        }
        /// <summary>
        /// CALLED FROM INVOKER. Run the activity in the provided context. Used to execute an activity within a workflow. If this activity metadata has not been added to the context it
        /// will be done now.
        /// </summary>
        /// <returns>True if completed, false if bookmarked.</returns>
        public bool ResumeInContext(IRunState runState, IWorkflowEvent resumeEvent)
        {
            bool hasCompleted = true;

            var resumable = this as IResumableActivity;

            if (resumable == null)
            {
                throw new ApplicationException("Attempted to resume an activity that is not resumable. This should never happen.");
            }

            hasCompleted = resumable.OnResume(runState, resumeEvent);

            if (hasCompleted && runState.ExitPointId == null)
            {
                runState.ExitPointId = ActivityInstance.GetDefaultExitPoint();
            }

            return(hasCompleted);
        }
Example #16
0
        bool IResumableActivity.OnResume(IRunState context, IWorkflowEvent resumeEvent)
        {
            bool hasCompleted = true;

            context.SyncFromRun();

            var currentActivity = context.PendingActivity;

            context.PendingActivity = null;

            if (currentActivity == null)
            {
                throw new ApplicationException("Current Activity missing from resumed activity. This should never occur.");
            }

            if (resumeEvent is WorkflowRestoreEvent)
            {
                if (context.RunStatus == WorkflowRunState_Enumeration.WorkflowRunCancelled)
                {
                    return(true);
                }

                // Unsuspend a workflow
                Debug.Assert(context.RunStatus == WorkflowRunState_Enumeration.WorkflowRunSuspended);
                ScheduleNextStep(context, currentActivity);
            }
            else
            {
                // Unpause an activity
                Debug.Assert(context.RunStatus == WorkflowRunState_Enumeration.WorkflowRunPaused);
                ScheduleResumeStep(context, resumeEvent, currentActivity);
            }

            hasCompleted = context.WorkflowInvoker.RunTillCompletion(context);

            return(hasCompleted);
        }
Example #17
0
        /// <summary>
        /// Resume workflow, the workflow runs immediatly in the current thread.
        /// </summary>
        /// <param name="run"></param>
        /// <param name="resumeEvent"></param>
        /// <param name="invoker"></param>
        /// <returns></returns>
        public WorkflowRun ResumeWorkflow(WorkflowRun run, IWorkflowEvent resumeEvent)
        {
            if (run == null)
            {
                throw new ArgumentNullException(nameof(run));
            }

            if (resumeEvent == null)
            {
                throw new ArgumentNullException(nameof(resumeEvent));
            }

            HandleDiagnostics(run, "Resumed");
            Factory.WorkflowRunTaskManager.RegisterStart(run.TaskId);

            using (new WorkflowRunContext {
                RunTriggersInCurrentThread = true
            })
            {
                run = ProcessWorkflowInContext(run, resumeEvent);
            }

            return(run);
        }
 public abstract bool OnResume(IRunState context, IWorkflowEvent resumeEvent);
Example #19
0
 public override WorkflowState Transition(IWorkflowEvent workflowEvent, Workflow workflow, object state)
 {
     return((workflowEvent.GetType() == typeof(UserLoggedIn)) ? new UserLoggedInState(workflow, state) : null);
 }
Example #20
0
 public override WorkflowState Transition(IWorkflowEvent workflowEvent, Workflow workflow, object state)
 {
     return(workflowEvent.GetType() == typeof(LoggedOut) ? new LoggedOutState(workflow) : null);
 }
Example #21
0
 public ValueTask OnTrigger(IExecutionContext context, IWorkflowEvent wfEvent, Object result)
 {
     SetComplete(context);
     ScheduleOutgoing(context);
     return(ValueTask.CompletedTask);
 }
Example #22
0
 /// <summary>
 /// Resume a paused activity on the invoker
 /// </summary>
 /// <param name="runState">The runstate</param>
 /// <param name="windowsActivity">The activity</param>
 /// <param name="resumeEvent">The trigger event for the resume</param>
 /// <returns></returns>
 public bool Resume(IRunState runState, ActivityImplementationBase windowsActivity, IWorkflowEvent resumeEvent)
 {
     ScheduleResume(runState, windowsActivity, resumeEvent, null, null);
     return(RunTillCompletion(runState));
 }
Example #23
0
        /// <summary>
        /// Add a resume activity to the pending list. NOTE! This does not resume the activity.
        ///
        /// </summary>
        public void ScheduleResume(IRunState runState, ActivityImplementationBase windowsActivity, IWorkflowEvent resumeEvent,
                                   Action <IRunState, ActivityImplementationBase, EntityRef> actionOnCompletion,
                                   Action <IRunState, ActivityImplementationBase> actionOnPause)
        {
            Func <bool> step = () =>
            {
                runState.RecordTrace(windowsActivity.ActivityInstance.Name);
                return(windowsActivity.ResumeInContext(runState, resumeEvent));
            };

            ProcessStep(runState, windowsActivity, actionOnCompletion, actionOnPause, step);
        }
Example #24
0
 public abstract WorkflowState Transition(IWorkflowEvent workflowEvent, Workflow workflow, object state);
Example #25
0
 public WorkflowRun ResumeWorkflow(WorkflowRun run, IWorkflowEvent resumeEvent)
 {
     throw new NotImplementedException();
 }
Example #26
0
 public string ResumeWorkflowAsync(WorkflowRun workflowRun, IWorkflowEvent resumeEvent)
 {
     throw new NotImplementedException();
 }
 public override WorkflowState Transition(IWorkflowEvent workflowEvent, Workflow workflow, object state)
 {
     return(null);
 }
 public override WorkflowState Transition(IWorkflowEvent workflowEvent, Workflow workflow, object state)
 {
     return(workflowEvent.GetType() == typeof(AdminLoggedIn) ? new AdministratorLoggedInState(workflow, state) : null);
 }
        /// <summary>
        /// Continue a paused activity
        /// </summary>
        /// <returns>True if the activity has completed, false if it is paused.</returns>
        public override bool OnResume(IRunState context, IWorkflowEvent resumeEvent)
        {
            HandleTimeout(context, resumeEvent);

            return(true);
        }
Example #30
0
        private WorkflowRun ProcessWorkflowInContext(WorkflowRun run, IWorkflowEvent wfEvent)
        {
            var workflow = run.WorkflowBeingRun;

            using (Profiler.Measure("WorkflowRunner.Instance.StartWorkflowInContext " + workflow.Id))
            {
                var stopWatch = StartWorkflowTimer();

                IRunState runState = null;

                try
                {
                    if (!run.IsTemporaryId)
                    {
                        PrecacheWorkflow(run.Id);
                    }

                    using (new SecurityBypassContext())
                    {
                        var metadata = MetadataFactory.Create(workflow);

                        runState = CreateRunState(metadata, run);

                        if (runState.EffectiveSecurityContext == null)
                        {
                            throw new WorkflowMissingOwnerException();
                        }
                    }

                    // Wrap a Security bypass with the effective context. This less us "Pop" to run as the effective context.
                    using (CustomContext.SetContext(runState.EffectiveSecurityContext))
                    {
                        using (new SecurityBypassContext())
                        {
                            if (runState.Metadata.HasViolations)
                            {
                                MarkRunFailedHasErrors(runState);
                            }
                            else if (run.TriggerDepth > WorkflowTriggerHelper.MaxTriggerDepth)
                            {
                                MarkRunFailedTriggerDepth(runState);
                            }
                            else
                            {
                                var isCompleted = ProcessWorkflow(workflow, runState, wfEvent);
                            }
                        }
                    }
                }
                catch (WorkflowRunException ex)
                {
                    MarkRunFailed(runState, ex);

                    if (runState != null)
                    {
                        runState.FlushInternalArgs();
                    }
                }
                catch (Exception ex)
                {
                    MarkRunInternalError(runState, ex);

                    if (runState != null)
                    {
                        runState.FlushInternalArgs();
                    }
                }
                finally
                {
                    if (!Factory.WorkflowRunTaskManager.HasCancelled(runState.RunTaskId))
                    {
                        run = FinalizeRun(runState);
                    }
                }

                EndWorkflowTimer(stopWatch);
            }

            return(run);
        }