示例#1
0
        private async Task <RunWorkflowResult> BeginWorkflow(WorkflowExecutionContext workflowExecutionContext, IActivityBlueprint?activity, CancellationToken cancellationToken)
        {
            if (activity == null)
            {
                activity = _startingActivitiesProvider.GetStartActivities(workflowExecutionContext.WorkflowBlueprint).FirstOrDefault() ?? workflowExecutionContext.WorkflowBlueprint.Activities.First();
            }

            try
            {
                if (!await CanExecuteAsync(workflowExecutionContext, activity, false, cancellationToken))
                {
                    return(new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, false));
                }

                workflowExecutionContext.Begin();
                workflowExecutionContext.ScheduleActivity(activity.Id);
                await RunAsync(workflowExecutionContext, Execute, cancellationToken);

                return(new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, true));
            }
            catch (Exception e)
            {
                _logger.LogWarning(e, "Failed to run workflow {WorkflowInstanceId}", workflowExecutionContext.WorkflowInstance.Id);
                workflowExecutionContext.Fault(e, null, null, false);
            }

            return(new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, false));
        }
示例#2
0
        private async Task <RunWorkflowResult> ResumeWorkflowAsync(WorkflowExecutionContext workflowExecutionContext, IActivityBlueprint activity, CancellationToken cancellationToken)
        {
            try
            {
                if (!await CanExecuteAsync(workflowExecutionContext, activity, true, cancellationToken))
                {
                    return(new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, null, false));
                }

                var blockingActivities = workflowExecutionContext.WorkflowInstance.BlockingActivities.Where(x => x.ActivityId == activity.Id).ToList();

                foreach (var blockingActivity in blockingActivities)
                {
                    await workflowExecutionContext.RemoveBlockingActivityAsync(blockingActivity);
                }

                var currentStatus = workflowExecutionContext.WorkflowInstance.WorkflowStatus;
                workflowExecutionContext.Resume();
                workflowExecutionContext.ScheduleActivity(activity.Id);
                await _mediator.Publish(new WorkflowStatusChanged(workflowExecutionContext.WorkflowInstance, workflowExecutionContext.WorkflowInstance.WorkflowStatus, currentStatus), cancellationToken);
                await RunCoreAsync(workflowExecutionContext, Resume, cancellationToken);

                return(new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, null, true));
            }
            catch (Exception e)
            {
                _logger.LogWarning(e, "Failed to run workflow {WorkflowInstanceId}", workflowExecutionContext.WorkflowInstance.Id);
                workflowExecutionContext.Fault(e, activity.Id, null, false);
                workflowExecutionContext.AddEntry(activity, "Faulted", null, SimpleException.FromException(e));
                return(new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, e, false));
            }
        }
示例#3
0
        private async Task <RunWorkflowResult> BeginWorkflow(WorkflowExecutionContext workflowExecutionContext, IActivityBlueprint?activity, CancellationToken cancellationToken)
        {
            if (activity == null)
            {
                activity = _startingActivitiesProvider.GetStartActivities(workflowExecutionContext.WorkflowBlueprint).FirstOrDefault() ?? workflowExecutionContext.WorkflowBlueprint.Activities.First();
            }

            try
            {
                if (!await CanExecuteAsync(workflowExecutionContext, activity, false, cancellationToken))
                {
                    return(new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, null, false));
                }

                var currentStatus = workflowExecutionContext.WorkflowInstance.WorkflowStatus;
                workflowExecutionContext.Begin();
                workflowExecutionContext.ScheduleActivity(activity.Id);
                await _mediator.Publish(new WorkflowStatusChanged(workflowExecutionContext.WorkflowInstance, workflowExecutionContext.WorkflowInstance.WorkflowStatus, currentStatus), cancellationToken);
                await RunCoreAsync(workflowExecutionContext, Execute, cancellationToken);

                return(new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity?.Id, null, true));
            }
            catch (Exception e)
            {
                _logger.LogWarning(e, "Failed to run workflow {WorkflowInstanceId}", workflowExecutionContext.WorkflowInstance.Id);
                workflowExecutionContext.Fault(e, activity?.Id, null, false);

                if (activity != null)
                {
                    workflowExecutionContext.AddEntry(activity, "Faulted", null, SimpleException.FromException(e));
                }

                return(new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity?.Id, e, false));
            }
        }
示例#4
0
 private void FaultWorkflow(WorkflowExecutionContext workflowContext, IActivity activity, Exception ex)
 {
     logger.LogError(
         ex,
         "An unhandled error occurred while executing an activity. Putting the workflow in the faulted state."
         );
     workflowContext.Fault(ex, activity, clock.GetCurrentInstant());
 }
示例#5
0
 private async ValueTask RunAsync(WorkflowExecutionContext workflowExecutionContext, ActivityOperation activityOperation, CancellationToken cancellationToken = default)
 {
     try
     {
         await RunCoreAsync(workflowExecutionContext, activityOperation, cancellationToken);
     }
     catch (Exception e)
     {
         _logger.LogWarning(e, "Failed to run workflow {WorkflowInstanceId}", workflowExecutionContext.WorkflowInstance.Id);
         workflowExecutionContext.Fault(e, null, null, activityOperation == Resume);
     }
 }
        public override async Task ExecuteAsync(
            IWorkflowInvoker invoker,
            WorkflowExecutionContext workflowContext,
            CancellationToken cancellationToken)
        {
            var eventHandlers   = workflowContext.ServiceProvider.GetServices <IWorkflowEventHandler>();
            var logger          = workflowContext.ServiceProvider.GetRequiredService <ILogger <FaultWorkflowResult> >();
            var currentActivity = workflowContext.CurrentActivity;

            await eventHandlers.InvokeAsync(
                x => x.ActivityFaultedAsync(workflowContext, currentActivity, errorMessage, cancellationToken),
                logger);

            workflowContext.Fault(workflowContext.CurrentActivity, errorMessage);
        }
示例#7
0
        private async Task <RunWorkflowResult> RunWorkflowAsync(WorkflowExecutionContext workflowExecutionContext, IActivityBlueprint?activity, CancellationToken cancellationToken)
        {
            try
            {
                await RunCoreAsync(workflowExecutionContext, Execute, cancellationToken);

                return(new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity?.Id, null, true));
            }
            catch (Exception e)
            {
                _logger.LogWarning(e, "Failed to run workflow {WorkflowInstanceId}", workflowExecutionContext.WorkflowInstance.Id);
                workflowExecutionContext.Fault(e, null, null, false);

                if (activity != null)
                {
                    workflowExecutionContext.AddEntry(activity, "Faulted", null, SimpleException.FromException(e));
                }

                return(new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity?.Id, e, false));
            }
        }
示例#8
0
        public async Task <IEnumerable <ActivityRecord> > ExecuteWorkflowAsync(WorkflowExecutionContext workflowContext, ActivityRecord activity)
        {
            var workflowType = workflowContext.WorkflowType;
            var scheduled    = new Stack <ActivityRecord>();
            var blocking     = new List <ActivityRecord>();
            var isResuming   = workflowContext.Status == WorkflowStatus.Resuming;
            var isFirstPass  = true;

            workflowContext.Status = WorkflowStatus.Executing;
            scheduled.Push(activity);

            while (scheduled.Count > 0)
            {
                activity = scheduled.Pop();

                var activityContext = workflowContext.GetActivity(activity.ActivityId);

                // Signal every activity that the activity is about to be executed.
                var cancellationToken = new CancellationToken();
                await InvokeActivitiesAsync(workflowContext, x => x.Activity.OnActivityExecutingAsync(workflowContext, activityContext, cancellationToken));

                if (cancellationToken.IsCancellationRequested)
                {
                    // Activity is aborted.
                    workflowContext.Status = WorkflowStatus.Aborted;
                    break;
                }

                IList <string> outcomes = new List <string>(0);

                try
                {
                    ActivityExecutionResult result;

                    if (!isResuming)
                    {
                        // Execute the current activity.
                        result = await activityContext.Activity.ExecuteAsync(workflowContext, activityContext);
                    }
                    else
                    {
                        // Resume the current activity.
                        result = await activityContext.Activity.ResumeAsync(workflowContext, activityContext);

                        isResuming = false;
                    }

                    if (result.IsHalted)
                    {
                        if (isFirstPass)
                        {
                            // Resume immediately when this is the first pass.
                            result = await activityContext.Activity.ResumeAsync(workflowContext, activityContext);

                            isFirstPass = false;
                            outcomes    = result.Outcomes;

                            if (result.IsHalted)
                            {
                                // Block on this activity.
                                blocking.Add(activity);
                            }
                        }
                        else
                        {
                            // Block on this activity.
                            blocking.Add(activity);

                            continue;
                        }
                    }
                    else
                    {
                        outcomes = result.Outcomes;
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "An unhandled error occurred while executing an activity. Workflow ID: '{WorkflowTypeId}'. Activity: '{ActivityId}', '{ActivityName}'. Putting the workflow in the faulted state.", workflowType.Id, activityContext.ActivityRecord.ActivityId, activityContext.ActivityRecord.Name);
                    workflowContext.Fault(ex, activityContext);
                    return(blocking.Distinct());
                }

                // Signal every activity that the activity is executed.
                await InvokeActivitiesAsync(workflowContext, x => x.Activity.OnActivityExecutedAsync(workflowContext, activityContext));

                foreach (var outcome in outcomes)
                {
                    // Look for next activity in the graph.
                    var transition = workflowType.Transitions.FirstOrDefault(x => x.SourceActivityId == activity.ActivityId && x.SourceOutcomeName == outcome);

                    if (transition != null)
                    {
                        var destinationActivity = workflowContext.WorkflowType.Activities.SingleOrDefault(x => x.ActivityId == transition.DestinationActivityId);
                        scheduled.Push(destinationActivity);
                    }
                }

                isFirstPass = false;
            }

            // Apply Distinct() as two paths could block on the same activity.
            var blockingActivities = blocking.Distinct().ToList();

            workflowContext.Status = blockingActivities.Any() || workflowContext.Workflow.BlockingActivities.Any() ? WorkflowStatus.Halted : WorkflowStatus.Finished;

            foreach (var blockingActivity in blockingActivities)
            {
                // Workflows containing event activities could end up being blocked on the same activity.
                if (!workflowContext.Workflow.BlockingActivities.Any(x => x.ActivityId == blockingActivity.ActivityId))
                {
                    workflowContext.Workflow.BlockingActivities.Add(BlockingActivity.FromActivity(blockingActivity));
                }
            }

            return(blockingActivities);
        }
示例#9
0
        protected override void Execute(IWorkflowInvoker invoker, WorkflowExecutionContext workflowContext)
        {
            var activity = workflowContext.CurrentActivity;

            workflowContext.Fault(errorMessage, activity);
        }