public async Task TriggerEventAsync(string name, IDictionary <string, object> input = null, string correlationId = null, bool isExclusive = false, bool isAlwaysCorrelated = false)
        {
            var activity = _activityLibrary.GetActivityByName(name);

            if (activity == null)
            {
                _logger.LogError("Activity '{ActivityName}' was not found", name);
                return;
            }

            // Look for workflow types with a corresponding starting activity.
            var workflowTypesToStart = await _workflowTypeStore.GetByStartActivityAsync(name);

            // And any workflow halted on this kind of activity for the specified target.
            var haltedWorkflows = await _workflowStore.ListByActivityNameAsync(name, correlationId, isAlwaysCorrelated);

            // If no workflow matches the event, do nothing.
            if (!workflowTypesToStart.Any() && !haltedWorkflows.Any())
            {
                return;
            }

            // Start new workflows.
            foreach (var workflowType in workflowTypesToStart)
            {
                // If this is a singleton workflow and there's already an halted instance, then skip.
                if (workflowType.IsSingleton && await _workflowStore.HasHaltedInstanceAsync(workflowType.WorkflowTypeId))
                {
                    continue;
                }

                // If the event is exclusive and there's already an instance halted on this activity type, then skip.
                if (isExclusive && haltedWorkflows.Any(x => x.WorkflowTypeId == workflowType.WorkflowTypeId))
                {
                    continue;
                }

                var startActivity = workflowType.Activities.FirstOrDefault(x => x.IsStart && String.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase));

                if (startActivity != null)
                {
                    await StartWorkflowAsync(workflowType, startActivity, input, correlationId);
                }
            }

            // Resume halted workflows.
            foreach (var workflow in haltedWorkflows)
            {
                var blockingActivities = workflow.BlockingActivities.Where(x => x.Name == name).ToList();

                foreach (var blockingActivity in blockingActivities)
                {
                    await ResumeWorkflowAsync(workflow, blockingActivity, input);
                }
            }
        }
Exemple #2
0
        public async Task TriggerEventAsync(string name, IDictionary <string, object> input = null, string correlationId = null, bool isExclusive = false, bool isAlwaysCorrelated = false)
        {
            var activity = _activityLibrary.GetActivityByName(name);

            if (activity == null)
            {
                _logger.LogError("Activity '{ActivityName}' was not found", name);
                return;
            }

            // Resume workflow instances halted on this kind of activity for the specified target.
            var haltedWorkflows = await _workflowStore.ListByActivityNameAsync(name, correlationId, isAlwaysCorrelated);

            foreach (var workflow in haltedWorkflows)
            {
                // Don't allow scope recursion per workflow instance id.
                if (_recursions.TryGetValue(workflow.WorkflowId, out var count) && count > 0)
                {
                    if (_logger.IsEnabled(LogLevel.Debug))
                    {
                        _logger.LogDebug("Don't allow scope recursion per workflow instance id: '{Workflow}'.", workflow.WorkflowId);
                    }

                    continue;
                }

                // If atomic, try to acquire a lock per workflow instance.
                (var locker, var locked) = await _distributedLock.TryAcquireWorkflowLockAsync(workflow);

                if (!locked)
                {
                    continue;
                }

                await using var acquiredLock = locker;

                // If atomic, check if the workflow still exists and is still correlated.
                var haltedWorkflow = workflow.IsAtomic ? await _workflowStore.GetAsync(workflow.Id) : workflow;

                if (haltedWorkflow == null || (!isAlwaysCorrelated && haltedWorkflow.CorrelationId != (correlationId ?? "")))
                {
                    continue;
                }

                // Check the max recursion depth of workflow executions.
                if (_currentRecursionDepth > MaxRecursionDepth)
                {
                    _logger.LogError("The max recursion depth of 'Workflow' executions has been reached.");
                    break;
                }

                var blockingActivities = haltedWorkflow.BlockingActivities.Where(x => x.Name == name).ToArray();
                foreach (var blockingActivity in blockingActivities)
                {
                    await ResumeWorkflowAsync(haltedWorkflow, blockingActivity, input);
                }
            }

            // Start new workflows whose types have a corresponding starting activity.
            var workflowTypesToStart = await _workflowTypeStore.GetByStartActivityAsync(name);

            foreach (var workflowType in workflowTypesToStart)
            {
                // Don't allow scope recursion per workflow type id.
                if (_recursions.TryGetValue(workflowType.WorkflowTypeId, out var count) && count > 0)
                {
                    if (_logger.IsEnabled(LogLevel.Debug))
                    {
                        _logger.LogDebug("Don't allow scope recursion per workflow type: '{WorkflowType}'.", workflowType.Name);
                    }

                    continue;
                }

                // If a singleton or the event is exclusive, try to acquire a lock per workflow type.
                (var locker, var locked) = await _distributedLock.TryAcquireWorkflowTypeLockAsync(workflowType, isExclusive);

                if (!locked)
                {
                    continue;
                }

                await using var acquiredLock = locker;

                // Check if this is a workflow singleton and there's already an halted instance on any activity.
                if (workflowType.IsSingleton && await _workflowStore.HasHaltedInstanceAsync(workflowType.WorkflowTypeId))
                {
                    continue;
                }

                // Check if the event is exclusive and there's already a correlated instance halted on a starting activity of this type.
                if (isExclusive && (await _workflowStore.ListAsync(workflowType.WorkflowTypeId, name, correlationId, isAlwaysCorrelated))
                    .Any(x => x.BlockingActivities.Any(x => x.Name == name && x.IsStart)))
                {
                    continue;
                }

                // Check the max recursion depth of workflow executions.
                if (_currentRecursionDepth > MaxRecursionDepth)
                {
                    _logger.LogError("The max recursion depth of 'Workflow' executions has been reached.");
                    break;
                }

                var startActivity = workflowType.Activities.First(x => x.IsStart && x.Name == name);
                await StartWorkflowAsync(workflowType, startActivity, input, correlationId);
            }
        }