public async Task <WorkflowExecutionContext> ResumeWorkflowAsync(Workflow workflow, BlockingActivity awaitingActivity, IDictionary <string, object> input = null) { var workflowType = await _workflowTypeStore.GetAsync(workflow.WorkflowTypeId); var activityRecord = workflowType.Activities.SingleOrDefault(x => x.ActivityId == awaitingActivity.ActivityId); var workflowContext = await CreateWorkflowExecutionContextAsync(workflowType, workflow, input); workflowContext.Status = WorkflowStatus.Resuming; // Signal every activity that the workflow is about to be resumed. var cancellationToken = new CancellationToken(); await InvokeActivitiesAsync(workflowContext, x => x.Activity.OnInputReceivedAsync(workflowContext, input)); await InvokeActivitiesAsync(workflowContext, x => x.Activity.OnWorkflowResumingAsync(workflowContext, cancellationToken)); if (cancellationToken.IsCancellationRequested) { // Workflow is aborted. workflowContext.Status = WorkflowStatus.Aborted; } else { // Check if the current activity can execute. if (activityRecord != null) { var activityContext = workflowContext.GetActivity(activityRecord.ActivityId); if (await activityContext.Activity.CanExecuteAsync(workflowContext, activityContext)) { // Signal every activity that the workflow is resumed. await InvokeActivitiesAsync(workflowContext, x => x.Activity.OnWorkflowResumedAsync(workflowContext)); // Remove the blocking activity. workflowContext.Workflow.BlockingActivities.Remove(awaitingActivity); // Resume the workflow at the specified blocking activity. await ExecuteWorkflowAsync(workflowContext, activityRecord); } else { workflowContext.Status = WorkflowStatus.Halted; return(workflowContext); } } } if (workflowContext.Status == WorkflowStatus.Finished && workflowType.DeleteFinishedWorkflows) { await _workflowStore.DeleteAsync(workflowContext.Workflow); } else { await PersistAsync(workflowContext); } return(workflowContext); }
protected override void Execute(ActivityExecutionContext activityExecutionContext) { var activityDefinition = activityExecutionContext.ActivityBlueprint; var blockingActivity = new BlockingActivity(activityDefinition.Id, activityDefinition.Type); activityExecutionContext.WorkflowExecutionContext.WorkflowInstance.BlockingActivities.Add(blockingActivity); activityExecutionContext.WorkflowExecutionContext.Suspend(); }
public override async ValueTask ExecuteAsync(ActivityExecutionContext activityExecutionContext, CancellationToken cancellationToken) { var activityDefinition = activityExecutionContext.ActivityBlueprint; var blockingActivity = new BlockingActivity(activityDefinition.Id, activityDefinition.Type); activityExecutionContext.WorkflowExecutionContext.WorkflowInstance.BlockingActivities.Add(blockingActivity); activityExecutionContext.WorkflowExecutionContext.Suspend(); var mediator = activityExecutionContext.ServiceProvider.GetRequiredService <IMediator>(); await mediator.Publish(new BlockingActivityAdded(activityExecutionContext.WorkflowExecutionContext, blockingActivity), cancellationToken); }
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); }
public BlockingActivityRemoved(WorkflowExecutionContext workflowExecutionContext, BlockingActivity blockingActivity) { WorkflowExecutionContext = workflowExecutionContext; BlockingActivity = blockingActivity; }