Esempio n. 1
0
        public async Task DispatchAsync(ExecuteWorkflowInstanceRequest request, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await _workflowInstanceStore.FindByIdAsync(request.WorkflowInstanceId, cancellationToken);

            if (workflowInstance == null)
            {
                _logger.LogWarning("Cannot dispatch a workflow instance ID that does not exist");
                return;
            }

            var workflowBlueprint = await _workflowRegistry.FindAsync(workflowInstance.DefinitionId, VersionOptions.SpecificVersion(workflowInstance.Version), workflowInstance.TenantId, cancellationToken);

            if (workflowBlueprint == null)
            {
                _logger.LogWarning("Workflow instance {WorkflowInstanceId} references workflow blueprint {WorkflowDefinitionId} with version {Version}, but could not be found",
                                   workflowInstance.Id,
                                   workflowInstance.DefinitionId,
                                   workflowInstance.Version);

                return;
            }

            var channel = _workflowChannelOptions.GetChannelOrDefault(workflowBlueprint.Channel);
            var queue   = ServiceBusOptions.FormatChannelQueueName <ExecuteWorkflowInstanceRequest>(channel);
            await _commandSender.SendAsync(request, queue, cancellationToken : cancellationToken);
        }
        public async Task <CancelWorkflowInstanceResult> CancelAsync(string workflowInstanceId, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await _workflowInstanceStore.FindByIdAsync(workflowInstanceId, cancellationToken);

            if (workflowInstance == null)
            {
                return(new CancelWorkflowInstanceResult(CancelWorkflowInstanceResultStatus.NotFound, null));
            }

            if (workflowInstance.WorkflowStatus != WorkflowStatus.Idle && workflowInstance.WorkflowStatus != WorkflowStatus.Running && workflowInstance.WorkflowStatus != WorkflowStatus.Suspended)
            {
                return(new CancelWorkflowInstanceResult(CancelWorkflowInstanceResultStatus.InvalidStatus, workflowInstance));
            }

            workflowInstance.BlockingActivities = new HashSet <BlockingActivity>();
            workflowInstance.CurrentActivity    = null;
            workflowInstance.WorkflowStatus     = WorkflowStatus.Cancelled;
            workflowInstance.CancelledAt        = _clock.GetCurrentInstant();

            await _workflowInstanceStore.SaveAsync(workflowInstance, cancellationToken);

            await _mediator.Publish(new WorkflowInstanceCancelled(workflowInstance), cancellationToken);

            return(new CancelWorkflowInstanceResult(CancelWorkflowInstanceResultStatus.Ok, workflowInstance));
        }
            public async Task StartAsync(CancellationToken cancellationToken)
            {
                var instance = await _workflowRunner.BuildAndStartWorkflowAsync <PersistableWorkflow>(cancellationToken : cancellationToken);

                var retrievedInstance = await _instanceStore.FindByIdAsync(instance.Id, cancellationToken);

                Assert.NotNull(retrievedInstance);
            }
Esempio n. 4
0
        protected override async ValueTask <IActivityExecutionResult> OnExecuteAsync(ActivityExecutionContext context)
        {
            var workflowInstance = await _workflowInstanceManager.FindByIdAsync(WorkflowInstanceId, context.CancellationToken);

            await _workflowTriggerInterruptor.InterruptActivityAsync(workflowInstance !, BlockingActivityId, Input, context.CancellationToken);

            return(Done());
        }
        public async Task <RunWorkflowResult> ExecuteAsync(string workflowInstanceId, string?activityId, WorkflowInput?input = default, CancellationToken cancellationToken = default)
        {
            var workflowInstanceLockKey           = $"workflow-instance:{workflowInstanceId}";
            var currentWorkflowInstanceLockHandle = AmbientLockContext.GetCurrentWorkflowInstanceLock(workflowInstanceId);
            var workflowInstanceLockHandle        = currentWorkflowInstanceLockHandle ?? await _distributedLockProvider.AcquireLockAsync(workflowInstanceLockKey, _elsaOptions.DistributedLockTimeout, cancellationToken);

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

            try
            {
                AmbientLockContext.SetCurrentWorkflowInstanceLock(workflowInstanceId, workflowInstanceLockHandle);
                var workflowInstance = await _workflowInstanceStore.FindByIdAsync(workflowInstanceId, cancellationToken);

                if (workflowInstance == null)
                {
                    _logger.LogWarning("Could not run workflow instance with ID {WorkflowInstanceId} because it does not exist", workflowInstanceId);
                    return(new RunWorkflowResult(workflowInstance, activityId, false));
                }

                var correlationId = workflowInstance.CorrelationId;

                if (!string.IsNullOrWhiteSpace(correlationId))
                {
                    // We need to lock on correlation ID to prevent a race condition with WorkflowLaunchpad that is used to find workflows by correlation ID to execute.
                    // The race condition is: when a workflow instance is done executing, the BookmarkIndexer will collect bookmarks.
                    // But if in the meantime an event comes in that triggers correlated workflows, the bookmarks may not have been created yet.
                    var currentCorrelationLockHandle = AmbientLockContext.CurrentCorrelationLock;
                    var correlationLockHandle        = currentCorrelationLockHandle ?? await _distributedLockProvider.AcquireLockAsync(correlationId, _elsaOptions.DistributedLockTimeout, cancellationToken);

                    if (correlationLockHandle == null)
                    {
                        throw new LockAcquisitionException($"Could not acquire a lock on correlation {correlationId} within the configured amount of time");
                    }

                    try
                    {
                        AmbientLockContext.CurrentCorrelationLock = correlationLockHandle;
                        return(await _workflowInstanceExecutor.ExecuteAsync(workflowInstance, activityId, input, cancellationToken));
                    }
                    finally
                    {
                        AmbientLockContext.CurrentCorrelationLock = null;
                        await correlationLockHandle.DisposeAsync();
                    }
                }

                return(await _workflowInstanceExecutor.ExecuteAsync(workflowInstance, activityId, input, cancellationToken));
            }
            finally
            {
                AmbientLockContext.DeleteCurrentWorkflowInstanceLock(workflowInstanceId);
                await workflowInstanceLockHandle.DisposeAsync();
            }
        }
Esempio n. 6
0
        public async Task Handle(WorkflowTestExecutionStopped notification, CancellationToken cancellationToken)
        {
            var workflowInstance = await _workflowInstanceStore.FindByIdAsync(notification.WorkflowInstanceId, cancellationToken);

            if (workflowInstance != null)
            {
                await _bookmarkIndexer.IndexBookmarksAsync(workflowInstance, cancellationToken);
            }
        }
        public async Task <RunWorkflowResult> ExecuteAsync(string workflowInstanceId, string?activityId, object?input = default, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await _workflowInstanceStore.FindByIdAsync(workflowInstanceId, cancellationToken);

            if (!ValidatePreconditions(workflowInstanceId, workflowInstance, activityId))
            {
                return(new RunWorkflowResult(workflowInstance, activityId, false));
            }

            return(await ExecuteAsync(workflowInstance !, activityId, input, cancellationToken));
        }
            public async Task StartAsync(CancellationToken cancellationToken)
            {
                var instance = await _workflowRunner.BuildAndStartWorkflowAsync <TWorkflow>(cancellationToken : cancellationToken);

                var retrievedInstance = await _instanceStore.FindByIdAsync(instance.Id, cancellationToken);

                // An instance should totally be retrieved from the store
                Assert.NotNull(retrievedInstance);
                // Because we are in-memory, it should be a reference to the same instance
                Assert.Same(instance, retrievedInstance);
            }
Esempio n. 9
0
        public async Task ResumeWorkflowsAsync(IEnumerable <BookmarkFinderResult> results, object?input = default, string?correlationId = default, string?contextId = default, CancellationToken cancellationToken = default)
        {
            foreach (var result in results)
            {
                var workflowInstance = await _workflowInstanceStore.FindByIdAsync(result.WorkflowInstanceId, cancellationToken);

                if (workflowInstance?.WorkflowStatus == WorkflowStatus.Suspended)
                {
                    await ResumeWorkflowAsync(workflowInstance !, result.ActivityId, input, cancellationToken);
                }
            }
        }
Esempio n. 10
0
        public async Task <DeleteWorkflowInstanceResult> DeleteAsync(string workflowInstanceId, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await _workflowInstanceStore.FindByIdAsync(workflowInstanceId, cancellationToken);

            if (workflowInstance == null)
            {
                return(new DeleteWorkflowInstanceResult(DeleteWorkflowInstanceResultStatus.NotFound, null));
            }

            await _workflowInstanceStore.DeleteAsync(workflowInstance, cancellationToken);

            return(new DeleteWorkflowInstanceResult(DeleteWorkflowInstanceResultStatus.Ok, workflowInstance));
        }
Esempio n. 11
0
        public async Task <IActionResult> Handle(string id, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await _workflowInstanceStore.FindByIdAsync(id, cancellationToken);

            if (workflowInstance == null)
            {
                return(NotFound());
            }

            await _workflowInstanceStore.DeleteAsync(workflowInstance, cancellationToken);

            return(NoContent());
        }
Esempio n. 12
0
        public async Task ResumeWorkflowsAsync(IEnumerable <BookmarkFinderResult> results, WorkflowInput?input = default, CancellationToken cancellationToken = default)
        {
            foreach (var result in results)
            {
                var workflowInstance = await _workflowInstanceStore.FindByIdAsync(result.WorkflowInstanceId, cancellationToken);

                if (workflowInstance?.WorkflowStatus == WorkflowStatus.Suspended)
                {
                    await _workflowStorageService.UpdateInputAsync(workflowInstance, input, cancellationToken);
                    await ResumeWorkflowAsync(workflowInstance !, result.ActivityId, cancellationToken);
                }
            }
        }
Esempio n. 13
0
        public async Task <Unit> Handle(ExecuteWorkflowInstanceRequest request, CancellationToken cancellationToken)
        {
            var workflowInstanceId = request.WorkflowInstanceId;
            var workflowInstance   = await _workflowInstanceStore.FindByIdAsync(request.WorkflowInstanceId, cancellationToken);

            if (!ValidatePreconditions(workflowInstanceId, workflowInstance, request.ActivityId))
            {
                return(Unit.Value);
            }

            await _workflowRunner.ResumeWorkflowAsync(
                workflowInstance !,
                request.ActivityId,
                request.Input, cancellationToken);

            return(Unit.Value);
        }
Esempio n. 14
0
        public async Task <IActionResult> Handle(string id, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await _workflowInstanceStore.FindByIdAsync(id, cancellationToken);

            if (workflowInstance == null)
            {
                return(NotFound());
            }

            var tenantId = await _tenantAccessor.GetTenantIdAsync(cancellationToken);

            var workflowBlueprint = await _workflowRegistry.FindByDefinitionVersionIdAsync(workflowInstance.DefinitionVersionId, tenantId, cancellationToken);

            await _publisher.Publish(new RequestingWorkflowInstance(workflowInstance, workflowBlueprint !), cancellationToken);

            return(Json(workflowInstance, _contentSerializer.GetSettings()));
        }
Esempio n. 15
0
        protected override async ValueTask <IActivityExecutionResult> OnExecuteAsync(ActivityExecutionContext context)
        {
            var cancellationToken = context.CancellationToken;
            var workflowInstance  = await _workflowInstanceManager.FindByIdAsync(WorkflowInstanceId, cancellationToken);

            if (workflowInstance == null)
            {
                throw new WorkflowException($"Could not find workflow instance by ID {WorkflowInstanceId}");
            }

            if (Input != null)
            {
                workflowInstance.Input = await _workflowStorageService.SaveAsync(new WorkflowInput(Input), workflowInstance, cancellationToken);
            }

            await _workflowTriggerInterruptor.InterruptActivityAsync(workflowInstance !, BlockingActivityId, cancellationToken);

            return(Done());
        }
Esempio n. 16
0
        public async Task <IActionResult> Handle(string id, RetryWorkflowRequest?options, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await _store.FindByIdAsync(id, cancellationToken);

            if (workflowInstance == null)
            {
                return(NotFound());
            }

            if (options?.RunImmediately == false)
            {
                workflowInstance = await _reviver.ReviveAndQueueAsync(workflowInstance, cancellationToken);

                var model = new
                {
                    WorkflowInstanceId = workflowInstance.Id,
                };

                return(Accepted(model));
            }

            var runWorkflowResult = await _reviver.ReviveAndRunAsync(workflowInstance, cancellationToken);

            workflowInstance = runWorkflowResult.WorkflowInstance !;

            if (workflowInstance.WorkflowStatus == WorkflowStatus.Faulted)
            {
                return(StatusCode(500, new
                {
                    WorkflowInstanceId = workflowInstance.Id,
                    Fault = workflowInstance.Fault
                }).ConfigureForEndpoint());
            }

            return(Response.HasStarted
                ? new EmptyResult()
                : Json(new
            {
                WorkflowInstanceId = workflowInstance.Id,
                WorkflowStatus = workflowInstance.WorkflowStatus
            }, _serializerSettingsProvider.GetSettings()));
        }
Esempio n. 17
0
        public async Task <IActionResult> Handle(string id, RetryWorkflowRequest?options, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await _store.FindByIdAsync(id, cancellationToken);

            if (workflowInstance == null)
            {
                return(NotFound());
            }

            if (options?.RunImmediately == false)
            {
                workflowInstance = await _reviver.ReviveAndQueueAsync(workflowInstance, cancellationToken);

                var model = new
                {
                    WorkflowInstanceId = workflowInstance.Id,
                };

                return(Accepted(model));
            }

            workflowInstance = await _reviver.ReviveAndRunAsync(workflowInstance, cancellationToken);

            if (workflowInstance.WorkflowStatus == WorkflowStatus.Faulted)
            {
                return(StatusCode(500, new
                {
                    WorkflowInstanceId = workflowInstance.Id,
                    Fault = workflowInstance.Fault
                }));
            }

            return(Response.HasStarted ? (IActionResult) new EmptyResult() : Ok(new
            {
                WorkflowInstanceId = workflowInstance.Id,
                WorkflowStatus = workflowInstance.WorkflowStatus
            }));
        }
Esempio n. 18
0
        public async Task <ActionResult <WorkflowInstance> > Handle(string id, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await _workflowInstanceStore.FindByIdAsync(id, cancellationToken);

            return(workflowInstance ?? (ActionResult <WorkflowInstance>)NotFound());
        }