public static bool WithVersion(this IWorkflowBlueprint workflowBlueprint, VersionOptions version)
 {
     if (version.IsDraft)
     {
         return(!workflowBlueprint.IsPublished);
     }
     if (version.IsLatest)
     {
         return(workflowBlueprint.IsLatest);
     }
     if (version.IsPublished)
     {
         return(workflowBlueprint.IsPublished);
     }
     if (version.IsLatestOrPublished)
     {
         return(workflowBlueprint.IsPublished || workflowBlueprint.IsLatest);
     }
     if (version.AllVersions)
     {
         return(true);
     }
     if (version.Version > 0)
     {
         return(workflowBlueprint.Version == version.Version);
     }
     return(true);
 }
Ejemplo n.º 2
0
        public virtual async Task <RunWorkflowResult> RunWorkflowAsync(
            IWorkflowBlueprint workflowBlueprint,
            WorkflowInstance workflowInstance,
            string?activityId = default,
            //WorkflowInput? workflowInput = default,
            CancellationToken cancellationToken = default)
        {
            using var loggingScope           = _logger.BeginScope(new Dictionary <string, object> { ["WorkflowInstanceId"] = workflowInstance.Id });
            using var workflowExecutionScope = _serviceScopeFactory.CreateScope();

            // var input = workflowInput?.Input ?? await _workflowStorageService.LoadAsync(workflowInstance, cancellationToken);
            //
            // // If input provided, update the workflow instance with this input.
            // if (input != null)
            //     workflowInstance.Input = await _workflowStorageService.SaveAsync(workflowInput!, workflowInstance, cancellationToken);
            // // If no input was provided, load the input associated with the workflow instance (if any).
            // else

            var input = await _workflowStorageService.LoadAsync(workflowInstance, cancellationToken);

            var workflowExecutionContext = new WorkflowExecutionContext(workflowExecutionScope.ServiceProvider, workflowBlueprint, workflowInstance, input);
            var result = await RunWorkflowInternalAsync(workflowExecutionContext, activityId, cancellationToken);

            await workflowExecutionContext.WorkflowExecutionLog.FlushAsync(cancellationToken);

            return(result);
        }
Ejemplo n.º 3
0
        public virtual async Task <RunWorkflowResult> RunWorkflowAsync(
            IWorkflowBlueprint workflowBlueprint,
            WorkflowInstance workflowInstance,
            string?activityId   = default,
            WorkflowInput?input = default,
            CancellationToken cancellationToken = default)
        {
            using var loggingScope           = _logger.BeginScope(new Dictionary <string, object> { ["WorkflowInstanceId"] = workflowInstance.Id });
            using var workflowExecutionScope = _serviceScopeFactory.CreateScope();

            if (input?.Input != null)
            {
                var workflowStorageContext = new WorkflowStorageContext(workflowInstance, workflowBlueprint.Id);
                var inputStorageProvider   = _workflowStorageService.GetProviderByNameOrDefault(input.StorageProviderName);
                await inputStorageProvider.SaveAsync(workflowStorageContext, nameof(WorkflowInstance.Input), input.Input, cancellationToken);

                workflowInstance.Input = new WorkflowInputReference(inputStorageProvider.Name);
                await _mediator.Publish(new WorkflowInputUpdated(workflowInstance), cancellationToken);
            }

            var workflowExecutionContext = new WorkflowExecutionContext(workflowExecutionScope.ServiceProvider, workflowBlueprint, workflowInstance, input?.Input);
            var result = await RunWorkflowInternalAsync(workflowExecutionContext, activityId, cancellationToken);

            await workflowExecutionContext.WorkflowExecutionLog.FlushAsync(cancellationToken);

            return(result);
        }
Ejemplo n.º 4
0
 public TriggerFinderResult(IWorkflowBlueprint workflowBlueprint, string activityId, string activityType, IBookmark bookmark)
 {
     WorkflowBlueprint = workflowBlueprint;
     ActivityId        = activityId;
     ActivityType      = activityType;
     Bookmark          = bookmark;
 }
        public static object?GetActivityPropertyRawValue(this IWorkflowBlueprint workflowBlueprint, string activityId, string propertyName)
        {
            var provider = workflowBlueprint.ActivityPropertyProviders.GetProvider(activityId, propertyName);
            var value    = provider?.RawValue;

            return(value);
        }
        public static async ValueTask <object?> EvaluateActivityPropertyValue(
            this IWorkflowBlueprint workflowBlueprint,
            string activityId,
            string propertyName,
            ActivityExecutionContext activityExecutionContext,
            CancellationToken cancellationToken)
        {
            var provider = workflowBlueprint.ActivityPropertyProviders.GetProvider(activityId, propertyName);
            var value    = provider != null ? await provider.GetValueAsync(activityExecutionContext, cancellationToken) : null;

            if (value == null)
            {
                // Get default value.
                var activityTypeService = activityExecutionContext.GetService <IActivityTypeService>();
                var activityBlueprint   = workflowBlueprint.GetActivity(activityId) !;
                var activityType        = await activityTypeService.GetActivityTypeAsync(activityBlueprint.Type, cancellationToken);

                var activityDescriptor = await activityTypeService.DescribeActivityType(activityType, cancellationToken);

                var propertyDescriptor = activityDescriptor.InputProperties.FirstOrDefault(x => x.Name == propertyName);

                value = propertyDescriptor?.DefaultValue;
            }

            return(value);
        }
Ejemplo n.º 7
0
 public WorkflowTrigger(IWorkflowBlueprint workflowBlueprint, string activityId, string activityType, string bookmarkHash, IBookmark bookmark)
 {
     WorkflowBlueprint = workflowBlueprint;
     ActivityId        = activityId;
     ActivityType      = activityType;
     BookmarkHash      = bookmarkHash;
     Bookmark          = bookmark;
 }
Ejemplo n.º 8
0
 public static async ValueTask<T?> GetActivityPropertyValue<T>(
     this IWorkflowBlueprint workflowBlueprint,
     string activityId,
     string propertyName,
     ActivityExecutionContext activityExecutionContext,
     CancellationToken cancellationToken)
 {
     var value = await workflowBlueprint.GetActivityPropertyValue(activityId, propertyName, activityExecutionContext, cancellationToken);
     return value == null ? default : (T) value;
 }
Ejemplo n.º 9
0
        public async Task <WorkflowInstance> InterruptActivityTypeAsync(IWorkflowBlueprint workflowBlueprint, WorkflowInstance workflowInstance, string activityType, object?input, CancellationToken cancellationToken)
        {
            var blockingActivities = workflowInstance.BlockingActivities.Where(x => x.ActivityType == activityType).ToList();

            foreach (var blockingActivity in blockingActivities)
            {
                workflowInstance = await InterruptActivityAsync(workflowBlueprint, workflowInstance, blockingActivity.ActivityId, input, cancellationToken);
            }

            return(workflowInstance);
        }
Ejemplo n.º 10
0
        public static async ValueTask<object?> GetActivityPropertyValue(
            this IWorkflowBlueprint workflowBlueprint,
            string activityId,
            string propertyName,
            ActivityExecutionContext activityExecutionContext,
            CancellationToken cancellationToken)
        {
            var provider = workflowBlueprint.ActivityPropertyProviders.GetProvider(activityId, propertyName);

            if (provider == null)
                return default!;
Ejemplo n.º 11
0
 public static ValueTask<T?> GetActivityPropertyValue<TActivity, T>(
     this IWorkflowBlueprint workflowBlueprint,
     string activityId,
     Expression<Func<TActivity, T>> propertyExpression,
     ActivityExecutionContext activityExecutionContext,
     CancellationToken cancellationToken) where TActivity : IActivity
 {
     var expression = (MemberExpression) propertyExpression.Body;
     string propertyName = expression.Member.Name;
     return GetActivityPropertyValue<T>(workflowBlueprint, activityId, propertyName, activityExecutionContext, cancellationToken);
 }
Ejemplo n.º 12
0
        public async ValueTask <WorkflowBlueprintModel> MapAsync(IWorkflowBlueprint workflowBlueprint, CancellationToken cancellationToken = default)
        {
            using var scope = _serviceScopeFactory.CreateScope();

            var wrapper = await _workflowBlueprintReflector.ReflectAsync(scope.ServiceProvider, workflowBlueprint, cancellationToken);

            var activityProperties = await Task.WhenAll(wrapper.Activities.Select(async x => (x.ActivityBlueprint.Id, await GetActivityPropertiesAsync(wrapper, x, cancellationToken))));

            var activityPropertyDictionary = activityProperties.ToDictionary(x => x.Id, x => x.Item2);

            return(_mapper.Map <WorkflowBlueprintModel>(workflowBlueprint, options => options.Items[ActivityBlueprintConverter.ActivityPropertiesKey] = activityPropertyDictionary));
        }
Ejemplo n.º 13
0
        public async Task <StartableWorkflow?> FindStartableWorkflowAsync(
            IWorkflowBlueprint workflowBlueprint,
            string?activityId,
            string?correlationId = default,
            string?contextId     = default,
            string?tenantId      = default,
            CancellationToken cancellationToken = default)
        {
            async Task <StartableWorkflow?> CollectWorkflows()
            {
                var startableWorkflowDefinition = await CollectStartableWorkflowInternalAsync(workflowBlueprint, activityId, correlationId, contextId, tenantId, cancellationToken);

                return(startableWorkflowDefinition != null ? await InstantiateStartableWorkflow(startableWorkflowDefinition, cancellationToken) : default);
        private async Task <IList <WorkflowTrigger> > GetTriggersForBookmarkProvider(
            IBookmarkProvider provider,
            BookmarkProviderContext context,
            IActivityBlueprint activityBlueprint,
            IWorkflowBlueprint workflowBlueprint,
            CancellationToken cancellationToken = default)
        {
            var bookmarkResults = (await provider.GetBookmarksAsync(context, cancellationToken)).ToList();

            return(bookmarkResults
                   .Select(x => new WorkflowTrigger(workflowBlueprint, activityBlueprint.Id, x.ActivityTypeName ?? activityBlueprint.Type, _bookmarkHasher.Hash(x.Bookmark), x.Bookmark))
                   .ToList());
        }
Ejemplo n.º 15
0
        private async Task <WorkflowInstance> TriggerSignalAsync(IWorkflowBlueprint workflowBlueprint, WorkflowInstance workflowInstance, string signal)
        {
            var workflowExecutionContext = new WorkflowExecutionContext(ServiceScope.ServiceProvider, workflowBlueprint, workflowInstance);
            var workflowBlueprintWrapper = new WorkflowBlueprintWrapper(workflowBlueprint, workflowExecutionContext);
            var activities              = workflowBlueprintWrapper.Activities.Where(x => x.ActivityBlueprint.Type == nameof(SignalReceived));
            var blockingActivityIds     = workflowInstance.BlockingActivities.Where(x => x.ActivityType == nameof(SignalReceived)).Select(x => x.ActivityId).ToList();
            var receiveSignalActivities = activities.Where(x => blockingActivityIds.Contains(x.ActivityBlueprint.Id)).ToList();
            var receiveSignal           = receiveSignalActivities.Single(activity => workflowBlueprintWrapper.GetActivity <SignalReceived>(activity.ActivityBlueprint.Id) !.EvaluatePropertyValueAsync(x => x.Signal).GetAwaiter().GetResult() == signal);

            var triggeredSignal = new Signal(signal);
            var result          = await WorkflowRunner.RunWorkflowAsync(workflowBlueprint, workflowInstance, receiveSignal.ActivityBlueprint.Id, new WorkflowInput(triggeredSignal));

            return(result.WorkflowInstance !);
        }
        private async Task <IEnumerable <WorkflowTrigger> > GetTriggersInternalAsync(IWorkflowBlueprint workflowBlueprint, IDictionary <string, ActivityType> activityTypes, CancellationToken cancellationToken)
        {
            var startingActivityBlueprints = _startingActivitiesProvider.GetStartActivities(workflowBlueprint);
            var workflowExecutionContext   = await _workflowExecutionContextFactory.CreateWorkflowExecutionContextAsync(workflowBlueprint, cancellationToken);

            var tasksOfCollectionsOfTriggers = startingActivityBlueprints
                                               .Select(async activityBlueprint => await _triggerProvider.GetTriggersForActivityBlueprintAsync(activityBlueprint,
                                                                                                                                              workflowExecutionContext,
                                                                                                                                              activityTypes,
                                                                                                                                              cancellationToken));

            return((await Task.WhenAll(tasksOfCollectionsOfTriggers))
                   .SelectMany(x => x)
                   .ToList());
        }
Ejemplo n.º 17
0
 public WorkflowExecutionContext(
     IServiceProvider serviceProvider,
     IWorkflowBlueprint workflowBlueprint,
     WorkflowInstance workflowInstance,
     object?input = default
     )
 {
     ServiceProvider   = serviceProvider;
     WorkflowBlueprint = workflowBlueprint;
     WorkflowInstance  = workflowInstance;
     Input             = input;
     IsFirstPass       = true;
     Serializer        = serviceProvider.GetRequiredService <JsonSerializer>();
     Mediator          = serviceProvider.GetRequiredService <IMediator>();
 }
Ejemplo n.º 18
0
        public async Task <StartableWorkflow?> CollectStartableWorkflowAsync(
            IWorkflowBlueprint workflowBlueprint,
            string?activityId,
            string?correlationId = default,
            string?contextId     = default,
            string?tenantId      = default,
            CancellationToken cancellationToken = default)
        {
            correlationId ??= Guid.NewGuid().ToString("N");

            // Acquire a lock on correlation ID to prevent duplicate workflow instances from being created.
            await using var correlationLockHandle = await AcquireLockAsync(correlationId, cancellationToken);

            return(await CollectStartableWorkflowInternalAsync(workflowBlueprint, activityId, correlationId, contextId, tenantId, cancellationToken));
        }
Ejemplo n.º 19
0
        private async Task <StartableWorkflow?> CollectStartableWorkflowInternalAsync(
            IWorkflowBlueprint workflowBlueprint,
            string?activityId,
            string correlationId,
            string?contextId = default,
            string?tenantId  = default,
            CancellationToken cancellationToken = default)
        {
            var workflowDefinitionId = workflowBlueprint.Id;

            if (!ValidatePreconditions(workflowDefinitionId, workflowBlueprint))
            {
                return(null);
            }

            // Acquire a lock on the workflow definition so that we can ensure singleton-workflows never execute more than one instance.
            var lockKey = $"execute-workflow-definition:tenant:{tenantId}:workflow-definition:{workflowDefinitionId}";

            await using var workflowDefinitionHandle = await AcquireLockAsync(lockKey, cancellationToken);

            if (workflowBlueprint.IsSingleton)
            {
                if (await GetWorkflowIsAlreadyExecutingAsync(tenantId, workflowDefinitionId))
                {
                    _logger.LogDebug("Workflow {WorkflowDefinitionId} is a singleton workflow and is already running", workflowDefinitionId);
                    return(null);
                }
            }

            var startActivities = _getsStartActivities.GetStartActivities(workflowBlueprint).Select(x => x.Id).ToHashSet();
            var startActivityId = activityId == null?startActivities.FirstOrDefault() : startActivities.Contains(activityId) ? activityId : default;

            if (startActivityId == null)
            {
                _logger.LogWarning("Cannot start workflow {WorkflowDefinitionId} with version {WorkflowDefinitionVersion} because it has no starting activities", workflowBlueprint.Id, workflowBlueprint.Version);
                return(null);
            }

            var workflowInstance = await _workflowFactory.InstantiateAsync(
                workflowBlueprint,
                correlationId,
                contextId,
                cancellationToken);

            await _workflowInstanceStore.SaveAsync(workflowInstance, cancellationToken);

            return(new StartableWorkflow(workflowBlueprint, workflowInstance, startActivityId));
        }
Ejemplo n.º 20
0
        private static async Task <object?> GetPropertyValueAsync(IWorkflowBlueprint workflowBlueprint, IActivityBlueprintWrapper activityBlueprintWrapper, ActivityInputDescriptor propertyDescriptor, CancellationToken cancellationToken)
        {
            if (propertyDescriptor.IsDesignerCritical)
            {
                try
                {
                    return(await activityBlueprintWrapper.EvaluatePropertyValueAsync(propertyDescriptor.Name, cancellationToken));
                }
                catch (Exception e)
                {
                    throw new WorkflowException("Failed to evaluate a designer-critical property value. Please make sure that the value does not rely on external context.", e);
                }
            }

            return(workflowBlueprint.GetActivityPropertyRawValue(activityBlueprintWrapper.ActivityBlueprint.Id, propertyDescriptor.Name));
        }
Ejemplo n.º 21
0
        public async Task <RunWorkflowResult> InterruptActivityAsync(IWorkflowBlueprint workflowBlueprint, WorkflowInstance workflowInstance, string activityId, object?input, CancellationToken cancellationToken)
        {
            if (workflowInstance.WorkflowStatus != WorkflowStatus.Suspended)
            {
                throw new WorkflowException("Cannot interrupt workflows that are not in the Suspended state.");
            }

            var blockingActivity = workflowInstance.BlockingActivities.SingleOrDefault(x => x.ActivityId == activityId);

            if (blockingActivity == null)
            {
                throw new WorkflowException($"No blocking activity with ID {activityId} found.");
            }

            return(await _workflowRunner.RunWorkflowAsync(workflowBlueprint, workflowInstance, activityId, input, cancellationToken));
        }
        public WorkflowExecutionContext(
            IServiceProvider serviceProvider,
            IWorkflowBlueprint workflowBlueprint,
            WorkflowInstance workflowInstance,
            object?input = default
            )
        {
            ServiceProvider   = serviceProvider;
            WorkflowBlueprint = workflowBlueprint;
            WorkflowInstance  = workflowInstance;
            Input             = input;
            IsFirstPass       = true;
            Serializer        = serviceProvider.GetRequiredService <JsonSerializer>();
            Mediator          = serviceProvider.GetRequiredService <IMediator>();

            // This is a service that needs to be bound to the same lifetime scope as the workflow execution context.
            WorkflowExecutionLog = ActivatorUtilities.CreateInstance <WorkflowExecutionLog>(serviceProvider);
        }
Ejemplo n.º 23
0
        public async Task <WorkflowInstance> StartWorkflowAsync(
            IWorkflowBlueprint workflowBlueprint,
            string?activityId    = default,
            object?input         = default,
            string?correlationId = default,
            string?contextId     = default,
            CancellationToken cancellationToken = default)
        {
            var workflowInstance = await _workflowFactory.InstantiateAsync(
                workflowBlueprint,
                correlationId,
                contextId,
                cancellationToken);

            await _workflowInstanceStore.SaveAsync(workflowInstance, cancellationToken);

            return(await _workflowRunner.RunWorkflowAsync(workflowBlueprint, workflowInstance, activityId, input, cancellationToken));
        }
Ejemplo n.º 24
0
        public async Task <RunWorkflowResult> FindAndExecuteStartableWorkflowAsync(
            IWorkflowBlueprint workflowBlueprint,
            string?activityId,
            string?correlationId = default,
            string?contextId     = default,
            WorkflowInput?input  = default,
            CancellationToken cancellationToken = default)
        {
            var workflowDefinitionId = workflowBlueprint.Id;
            var tenantId             = workflowBlueprint.TenantId;

            var startableWorkflow = await FindStartableWorkflowAsync(workflowBlueprint, activityId, correlationId, contextId, tenantId, cancellationToken);

            if (startableWorkflow == null)
            {
                throw new WorkflowException($"Could not start workflow with ID {workflowDefinitionId}");
            }

            return(await ExecuteStartableWorkflowAsync(startableWorkflow, input, cancellationToken));
        }
Ejemplo n.º 25
0
        public async Task <WorkflowInstance> RunWorkflowAsync(
            IWorkflowBlueprint workflowBlueprint,
            WorkflowInstance workflowInstance,
            string?activityId = default,
            object?input      = default,
            CancellationToken cancellationToken = default)
        {
            var key = $"locking-workflow-runner:{workflowInstance.Id}";

            await using var handle = await _distributedLockProvider.AcquireLockAsync(key, _elsaOptions.DistributedLockTimeout, cancellationToken);

            if (handle == null)
            {
                throw new LockAcquisitionException("Could not acquire a lock within the configured amount of time");
            }

            workflowInstance = await _workflowRunner.RunWorkflowAsync(workflowBlueprint, workflowInstance, activityId, input, cancellationToken);

            await handle.DisposeAsync();

            return(workflowInstance);
        }
Ejemplo n.º 26
0
        public async Task <RunWorkflowResult> StartWorkflowAsync(
            IWorkflowBlueprint workflowBlueprint,
            string?activityId    = default,
            WorkflowInput?input  = default,
            string?correlationId = default,
            string?contextId     = default,
            string?tenantId      = default,
            CancellationToken cancellationToken = default)
        {
            var workflowInstance = await _workflowFactory.InstantiateAsync(
                workflowBlueprint,
                correlationId,
                contextId,
                tenantId,
                cancellationToken);

            await _workflowStorageService.UpdateInputAsync(workflowInstance, input, cancellationToken);

            await _workflowInstanceStore.SaveAsync(workflowInstance, cancellationToken);

            return(await _workflowRunner.RunWorkflowAsync(workflowBlueprint, workflowInstance, activityId, cancellationToken));
        }
Ejemplo n.º 27
0
        public Task <WorkflowInstance> InstantiateAsync(
            IWorkflowBlueprint workflowBlueprint,
            string?correlationId = default,
            string?contextId     = default,
            CancellationToken cancellationToken = default)
        {
            var workflowInstance = new WorkflowInstance
            {
                Id             = _idGenerator.Generate(),
                DefinitionId   = workflowBlueprint.Id,
                TenantId       = workflowBlueprint.TenantId,
                Version        = workflowBlueprint.Version,
                WorkflowStatus = WorkflowStatus.Idle,
                CorrelationId  = correlationId,
                ContextId      = contextId,
                CreatedAt      = _clock.GetCurrentInstant(),
                Variables      = new Variables(workflowBlueprint.Variables),
                ContextType    = workflowBlueprint.ContextOptions?.ContextType?.GetContextTypeName()
            };

            return(Task.FromResult(workflowInstance));
        }
Ejemplo n.º 28
0
        private static async Task <bool> WorkflowHasNonFinishedWorkflowsAsync(IWorkflowBlueprint workflowBlueprint, IWorkflowInstanceStore workflowInstanceStore, CancellationToken cancellationToken)
        {
            var count = await workflowInstanceStore.CountAsync(new UnfinishedWorkflowSpecification().WithWorkflowDefinition(workflowBlueprint.Id), cancellationToken);

            return(count > 0);
        }
Ejemplo n.º 29
0
        private IDictionary <string, IDictionary <string, object?> > GetActivityDataFromLastWorkflowInstance(WorkflowInstance lastWorkflowInstance, IWorkflowBlueprint workflowBlueprint, string startingActivityId)
        {
            IDictionary <string, IDictionary <string, object?> > CollectSourceActivityData(string targetActivityId, IDictionary <string, IDictionary <string, object?> > activityDataAccumulator)
            {
                var sourceActivityId = workflowBlueprint.Connections.FirstOrDefault(x => x.Target.Activity.Id == targetActivityId)?.Source.Activity.Id;

                if (sourceActivityId == null)
                {
                    return(activityDataAccumulator);
                }

                activityDataAccumulator.Add(sourceActivityId, lastWorkflowInstance.ActivityData.GetItem(sourceActivityId));

                return(CollectSourceActivityData(sourceActivityId, activityDataAccumulator));
            }

            return(CollectSourceActivityData(startingActivityId, new Dictionary <string, IDictionary <string, object?> >()));
        }
Ejemplo n.º 30
0
        public virtual async Task <RunWorkflowResult> RunWorkflowAsync(
            IWorkflowBlueprint workflowBlueprint,
            WorkflowInstance workflowInstance,
            string?activityId = default,
            object?input      = default,
            CancellationToken cancellationToken = default)
        {
            using var loggingScope           = _logger.BeginScope(new Dictionary <string, object> { ["WorkflowInstanceId"] = workflowInstance.Id });
            using var workflowExecutionScope = _serviceScopeFactory.CreateScope();
            var workflowExecutionContext = new WorkflowExecutionContext(workflowExecutionScope.ServiceProvider, workflowBlueprint, workflowInstance, input);

            if (!string.IsNullOrWhiteSpace(workflowInstance.ContextId))
            {
                var loadContext = new LoadWorkflowContext(workflowExecutionContext);
                workflowExecutionContext.WorkflowContext = await _workflowContextManager.LoadContext(loadContext, cancellationToken);
            }

            // If the workflow instance has a CurrentActivity, it means the workflow instance is being retried.
            var currentActivity = workflowInstance.CurrentActivity;

            if (currentActivity != null)
            {
                activityId = currentActivity.ActivityId;
            }

            var activity = activityId != null?workflowBlueprint.GetActivity(activityId) : default;

            // Give application a chance to prevent workflow from executing.
            var validateWorkflowExecution = new ValidateWorkflowExecution(workflowExecutionContext, activity);
            await _mediator.Publish(validateWorkflowExecution, cancellationToken);

            if (!validateWorkflowExecution.CanExecuteWorkflow)
            {
                _logger.LogInformation("Workflow execution prevented for workflow {WorkflowInstanceId}", workflowInstance.Id);
                return(new RunWorkflowResult(workflowInstance, activityId, false));
            }

            await _mediator.Publish(new WorkflowExecuting(workflowExecutionContext), cancellationToken);

            RunWorkflowResult runWorkflowResult;

            switch (workflowExecutionContext.Status)
            {
            case WorkflowStatus.Idle:
                runWorkflowResult = await BeginWorkflow(workflowExecutionContext, activity, cancellationToken);

                if (!runWorkflowResult.Executed)
                {
                    _logger.LogDebug("Workflow {WorkflowInstanceId} cannot begin from an idle state (perhaps it needs a specific input)", workflowInstance.Id);
                    return(runWorkflowResult);
                }

                break;

            case WorkflowStatus.Running:
                await RunWorkflowAsync(workflowExecutionContext, cancellationToken);

                runWorkflowResult = new RunWorkflowResult(workflowInstance, activityId, true);
                break;

            case WorkflowStatus.Suspended:
                runWorkflowResult = await ResumeWorkflowAsync(workflowExecutionContext, activity !, cancellationToken);

                if (!runWorkflowResult.Executed)
                {
                    _logger.LogDebug("Workflow {WorkflowInstanceId} cannot be resumed from a suspended state (perhaps it needs a specific input)", workflowInstance.Id);
                    return(runWorkflowResult);
                }

                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            await _mediator.Publish(new WorkflowExecuted(workflowExecutionContext), cancellationToken);

            var statusEvent = workflowExecutionContext.Status switch
            {
                WorkflowStatus.Cancelled => new WorkflowCancelled(workflowExecutionContext),
                WorkflowStatus.Finished => new WorkflowCompleted(workflowExecutionContext),
                WorkflowStatus.Faulted => new WorkflowFaulted(workflowExecutionContext),
                WorkflowStatus.Suspended => new WorkflowSuspended(workflowExecutionContext),
                _ => default(INotification)
            };

            if (statusEvent != null)
            {
                _logger.LogTrace("Publishing a status event of type {EventType} for workflow {WorkflowInstanceId}", statusEvent.GetType().Name, workflowInstance.Id);
                await _mediator.Publish(statusEvent, cancellationToken);
            }

            await _mediator.Publish(new WorkflowExecutionFinished(workflowExecutionContext), cancellationToken);

            return(runWorkflowResult);
        }