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); }