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)); }
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)); } }
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)); } }
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()); }
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); }
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)); } }
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); }
protected override void Execute(IWorkflowInvoker invoker, WorkflowExecutionContext workflowContext) { var activity = workflowContext.CurrentActivity; workflowContext.Fault(errorMessage, activity); }