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); } } }
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); } }