Exemplo n.º 1
0
        private async Task ResumeIdleWorkflows(CancellationToken cancellationToken)
        {
            var instances = await _workflowInstanceStore.FindManyAsync(new WorkflowStatusSpecification(WorkflowStatus.Idle), cancellationToken : cancellationToken).ToList();

            if (instances.Any())
            {
                _logger.LogInformation("Found {WorkflowInstanceCount} workflows with status 'Idle'. Resuming each one of them", instances.Count);
            }
            else
            {
                _logger.LogInformation("Found no workflows with status 'Id'. Nothing to resume");
            }

            foreach (var instance in instances)
            {
                await using var correlationLockHandle = await _distributedLockProvider.AcquireLockAsync(instance.CorrelationId, _elsaOptions.DistributedLockTimeout, cancellationToken);

                if (correlationLockHandle == null)
                {
                    _logger.LogWarning("Failed to acquire lock on correlation {CorrelationId} for workflow instance {WorkflowInstanceId}", instance.CorrelationId, instance.Id);
                    continue;
                }

                _logger.LogInformation("Resuming {WorkflowInstanceId}", instance.Id);

                var input = await GetWorkflowInputAsync(instance, cancellationToken);

                await _workflowInstanceDispatcher.DispatchAsync(new ExecuteWorkflowInstanceRequest(instance.Id, Input : input), cancellationToken);
            }
        }
Exemplo n.º 2
0
        private async IAsyncEnumerable <WorkflowInstance> InterruptActivityTypeInternalAsync(string activityType, object?input, [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            var suspendedWorkflows = await _workflowInstanceStore.FindManyAsync(new BlockingActivityTypeSpecification(activityType), cancellationToken : cancellationToken).ToList();

            var workflowInstanceIds = suspendedWorkflows.Select(x => x.Id).Distinct().ToList();
            var workflowInstances   = await _workflowInstanceStore.FindManyAsync(new ManyWorkflowInstanceIdsSpecification(workflowInstanceIds), cancellationToken : cancellationToken).ToDictionary(x => x.Id);

            foreach (var suspendedWorkflow in suspendedWorkflows)
            {
                var workflowInstance = workflowInstances[suspendedWorkflow.Id];
                yield return(await InterruptActivityTypeAsync(workflowInstance, activityType, input, cancellationToken));
            }
        }
Exemplo n.º 3
0
        public async Task ExecuteAsync(CancellationToken cancellationToken = default)
        {
            var threshold     = _clock.GetCurrentInstant().Minus(_options.TimeToLive);
            var specification = new WorkflowCreatedBeforeSpecification(threshold);
            var currentPage   = 0;
            var take          = _options.BatchSize;
            var orderBy       = new OrderBy <WorkflowInstance>(x => x.CreatedAt, SortDirection.Descending);
            var collectedWorkflowInstanceIds = new List <string>();

            // Collect workflow instances to be deleted.
            while (true)
            {
                var paging = Paging.Page(currentPage++, take);

                var workflowInstances = await _workflowInstanceStore
                                        .FindManyAsync(specification, orderBy, paging, cancellationToken)
                                        .ToList();

                var filteredWorkflowInstances = await _retentionFilterPipeline.FilterAsync(workflowInstances, cancellationToken).ToList();

                collectedWorkflowInstanceIds.AddRange(filteredWorkflowInstances.Select(x => x.Id));

                if (workflowInstances.Count < take)
                {
                    break;
                }
            }

            // Delete collected workflow instances.
            await DeleteManyAsync(collectedWorkflowInstanceIds, cancellationToken);
        }
Exemplo n.º 4
0
        private async IAsyncEnumerable <IWorkflowBlueprint> ListActiveInternalAsync([EnumeratorCancellation] CancellationToken cancellationToken)
        {
            var workflows = await ListInternalAsync(cancellationToken).ToListAsync(cancellationToken);

            var publishedWorkflows = workflows.Where(x => x.IsPublished);

            foreach (var publishedWorkflow in publishedWorkflows)
            {
                yield return(publishedWorkflow);
            }

            // We also need to consider unpublished workflows for inclusion in case they still have associated active workflow instances.
            var unpublishedWorkflows   = workflows.Where(x => !x.IsPublished).ToDictionary(x => x.VersionId);
            var unpublishedWorkflowIds = unpublishedWorkflows.Keys;

            if (!unpublishedWorkflowIds.Any())
            {
                yield break;
            }

            var activeWorkflowInstances = await _workflowInstanceStore.FindManyAsync(new UnfinishedWorkflowSpecification().WithWorkflowDefinitionVersionIds(unpublishedWorkflowIds), cancellationToken : cancellationToken).ToList();

            var activeUnpublishedWorkflowVersionIds = activeWorkflowInstances.Select(x => x.DefinitionVersionId).Distinct().ToList();
            var activeUnpublishedWorkflowVersions   = unpublishedWorkflows.Where(x => activeUnpublishedWorkflowVersionIds.Contains(x.Key)).Select(x => x.Value);

            foreach (var unpublishedWorkflow in activeUnpublishedWorkflowVersions)
            {
                yield return(unpublishedWorkflow);
            }
        }
Exemplo n.º 5
0
        public async Task <IActionResult> Handle(
            [FromQuery(Name = "workflow")] string?workflowDefinitionId = default,
            [FromQuery(Name = "status")] WorkflowStatus?workflowStatus = default,
            [FromQuery] string?correlationId = default,
            [FromQuery] OrderBy?orderBy      = default,
            [FromQuery] string?searchTerm    = default,
            int page     = 0,
            int pageSize = 25,
            CancellationToken cancellationToken = default)
        {
            _stopwatch.Restart();
            var specification = Specification <WorkflowInstance> .Identity;

            if (!string.IsNullOrWhiteSpace(workflowDefinitionId))
            {
                specification = specification.WithWorkflowDefinition(workflowDefinitionId);
            }

            if (!string.IsNullOrWhiteSpace(correlationId))
            {
                specification = specification.WithCorrelationId(correlationId);
            }

            if (workflowStatus != null)
            {
                specification = specification.WithStatus(workflowStatus.Value);
            }

            if (!string.IsNullOrWhiteSpace(searchTerm))
            {
                specification = specification.WithSearchTerm(searchTerm);
            }

            var orderBySpecification = default(OrderBy <WorkflowInstance>);

            if (orderBy != null)
            {
                orderBySpecification = orderBy switch
                {
                    OrderBy.Started => OrderBySpecification.OrderByDescending <WorkflowInstance>(x => x.CreatedAt),
                    OrderBy.LastExecuted => OrderBySpecification.OrderByDescending <WorkflowInstance>(x => x.LastExecutedAt !),
                    OrderBy.Finished => OrderBySpecification.OrderByDescending <WorkflowInstance>(x => x.FinishedAt !),
                    _ => OrderBySpecification.OrderByDescending <WorkflowInstance>(x => x.FinishedAt !)
                };
            }

            var totalCount = await _workflowInstanceStore.CountAsync(specification, cancellationToken : cancellationToken);

            var paging            = Paging.Page(page, pageSize);
            var workflowInstances = await _workflowInstanceStore.FindManyAsync(specification, orderBySpecification, paging, cancellationToken).ToList();

            var items = _mapper.Map <ICollection <WorkflowInstanceSummaryModel> >(workflowInstances);

            _stopwatch.Stop();
            _logger.LogDebug("Handle took {TimeElapsed}", _stopwatch.Elapsed);
            var model = new PagedList <WorkflowInstanceSummaryModel>(items, page, pageSize, totalCount);

            return(Json(model, _contentSerializer.GetSettings()));
        }
    }
Exemplo n.º 6
0
        public async Task ExecuteAsync(CancellationToken cancellationToken = default)
        {
            await using var handle = await _distributedLockProvider.AcquireLockAsync(GetType ().Name, _elsaOptions.DistributedLockTimeout, cancellationToken);

            if (handle == null)
            {
                return;
            }

            var instances = await _workflowInstanceStore.FindManyAsync(new WorkflowStatusSpecification(WorkflowStatus.Running), cancellationToken : cancellationToken).ToList();

            if (instances.Any())
            {
                _logger.LogInformation("Found {WorkflowInstanceCount} workflows with status 'Running'. Resuming each one of them", instances.Count);
            }
            else
            {
                _logger.LogInformation("Found no workflows with status 'Running'. Nothing to resume");
            }

            foreach (var instance in instances)
            {
                await using var correlationLockHandle = await _distributedLockProvider.AcquireLockAsync(instance.CorrelationId, _elsaOptions.DistributedLockTimeout, cancellationToken);

                if (handle == null)
                {
                    _logger.LogWarning("Failed to acquire lock on correlation {CorrelationId} for workflow instance {WorkflowInstanceId}", instance.CorrelationId, instance.Id);
                    continue;
                }

                _logger.LogInformation("Resuming {WorkflowInstanceId}", instance.Id);
                var scheduledActivities = instance.ScheduledActivities;

                if (instance.CurrentActivity == null && !scheduledActivities.Any())
                {
                    if (instance.BlockingActivities.Any())
                    {
                        _logger.LogWarning(
                            "Workflow '{WorkflowInstanceId}' was in the Running state, but has no scheduled activities not has a currently executing one. However, it does have blocking activities, so switching to Suspended status",
                            instance.Id);

                        instance.WorkflowStatus = WorkflowStatus.Suspended;
                        await _workflowInstanceStore.SaveAsync(instance, cancellationToken);

                        continue;
                    }

                    _logger.LogWarning("Workflow '{WorkflowInstanceId}' was in the Running state, but has no scheduled activities nor has a currently executing one", instance.Id);
                    continue;
                }

                var scheduledActivity = instance.CurrentActivity ?? instance.ScheduledActivities.Peek();

                await _workflowInstanceDispatcher.DispatchAsync(new ExecuteWorkflowInstanceRequest(instance.Id, scheduledActivity.ActivityId), cancellationToken);
            }
        }
Exemplo n.º 7
0
        public async Task <IActionResult> Handle(BulkRetryWorkflowsRequest request, CancellationToken cancellationToken = default)
        {
            var workflowInstances        = (await _store.FindManyAsync(new WorkflowInstanceIdsSpecification(request.WorkflowInstanceIds), cancellationToken: cancellationToken)).ToList();
            var faultedWorkflowInstances = workflowInstances.Where(x => x.WorkflowStatus == WorkflowStatus.Faulted).ToList();

            foreach (var workflowInstance in faultedWorkflowInstances)
            {
                await _reviver.ReviveAndQueueAsync(workflowInstance, cancellationToken);
            }

            return(Json(new
            {
                ScheduledWorkflowCount = faultedWorkflowInstances.Count
            }, _serializerSettingsProvider.GetSettings()));
        }
Exemplo n.º 8
0
        private async IAsyncEnumerable <RunWorkflowResult> InterruptActivityTypeInternalAsync(string activityType, WorkflowInput?input, [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            var bookmarks = await _bookmarkFinder.FindBookmarksAsync(activityType, Enumerable.Empty <IBookmark>(), cancellationToken : cancellationToken);

            var workflowInstanceIds = bookmarks.Select(x => x.WorkflowInstanceId).Distinct().ToList();
            var workflowInstances   = await _workflowInstanceStore.FindManyAsync(new ManyWorkflowInstanceIdsSpecification(workflowInstanceIds), cancellationToken : cancellationToken);

            foreach (var workflowInstance in workflowInstances)
            {
                var results = await InterruptActivityTypeAsync(workflowInstance, activityType, input, cancellationToken);

                foreach (var result in results)
                {
                    yield return(result);
                }
            }
        }
Exemplo n.º 9
0
        public async Task ExecuteAsync(CancellationToken cancellationToken = default)
        {
            var            threshold     = _clock.GetCurrentInstant().Minus(_options.TimeToLive);
            var            specification = new WorkflowCreatedBeforeSpecification(threshold).And(new WorkflowFinishedStatusSpecification());
            var            take          = _options.PageSize;
            IList <string> workflowInstanceIds;

            do
            {
                workflowInstanceIds = (await _workflowInstanceStore.FindManyAsync(specification, new OrderBy <WorkflowInstance>(x => x.CreatedAt, SortDirection.Descending), new Paging(0, take), cancellationToken: cancellationToken))
                                      .Select(x => x.Id).ToList();
                _logger.LogInformation("Deleting {WorkflowInstanceCount} workflow instances", workflowInstanceIds.Count);

                if (workflowInstanceIds.Any())
                {
                    await DeleteManyAsync(workflowInstanceIds, cancellationToken);
                }
            } while (workflowInstanceIds.Any());
        }
 public Task <IEnumerable <WorkflowInstance> > FindManyAsync(ISpecification <WorkflowInstance> specification, IOrderBy <WorkflowInstance>?orderBy = default, IPaging?paging = default, CancellationToken cancellationToken = default) =>
 _store.FindManyAsync(specification, orderBy, paging, cancellationToken);