/// <inheritdoc/>
 public virtual async Task CorrelateAsync(V1CorrelationContext context, CancellationToken cancellationToken = default)
 {
     if (context == null)
     {
         throw new ArgumentNullException(nameof(context));
     }
     await this.SignalStream.WriteAsync(new(V1RuntimeSignalType.Correlate, Dynamic.FromObject(context)), cancellationToken);
 }
Esempio n. 2
0
        /// <summary>
        /// Performs a correlation on a <see cref="V1Event"/>, in a given <see cref="V1CorrelationContext"/> and using the specified <see cref="V1EventFilter"/>
        /// </summary>
        /// <param name="correlation">The <see cref="V1Correlation"/> to perform</param>
        /// <param name="correlationContext">The <see cref="V1CorrelationContext"/> in which to perform the <see cref="V1Correlation"/></param>
        /// <param name="e">The <see cref="V1Event"/> to correlate</param>
        /// <param name="filter">The <see cref="V1EventFilter"/> used to correlate the <see cref="V1Event"/></param>
        /// <param name="cancellationToken">A <see cref="CancellationToken"/></param>
        /// <returns>A new awaitable <see cref="Task"/></returns>
        protected virtual async Task CorrelateAsync(V1Correlation correlation, V1CorrelationContext correlationContext, V1Event e, V1EventFilter filter, CancellationToken cancellationToken = default)
        {
            this.Logger.LogInformation("Correlating event to context with id '{contextId}'...", correlationContext.Id);
            correlationContext.Correlate(e, filter.CorrelationMappings.Keys, true);
            correlation = await this.Correlations.UpdateAsync(correlation, cancellationToken);

            await this.Correlations.SaveChangesAsync(cancellationToken);

            this.Logger.LogInformation("Event successfully correlated to context with id '{contextId}'", correlationContext.Id);
            this.Logger.LogInformation("Attempting to complete the correlation with id '{correlationId}' in context with id '{contextId}'...", correlation.Id, correlationContext.Id);
            if (!correlation.TryComplete(correlationContext))
            {
                this.Logger.LogInformation("Correlations conditions are not met in the specified correlation context");
                return;
            }
            this.Logger.LogInformation("Correlation with id '{correlationId}' has been completed in context with id '{contextId}. Computing outcome...", correlation.Id, correlationContext.Id);
            switch (correlation.Outcome.Type)
            {
            case V1CorrelationOutcomeType.Start:
                await this.Mediator.ExecuteAndUnwrapAsync(new V1CreateWorkflowInstanceCommand(correlation.Outcome.Target, V1WorkflowInstanceActivationType.Trigger, new(), correlationContext, true, null), cancellationToken);

                break;

            case V1CorrelationOutcomeType.Correlate:
                await this.Mediator.ExecuteAndUnwrapAsync(new V1CorrelateWorkflowInstanceCommand(correlation.Outcome.Target, correlationContext), cancellationToken);

                break;

            default:
                throw new NotSupportedException($"The specified {nameof(V1CorrelationOutcomeType)} '{correlation.Outcome.Type}' is not supported");
            }
            correlation.ReleaseContext(correlationContext);
            correlation = await this.Correlations.UpdateAsync(correlation, cancellationToken);

            await this.Correlations.SaveChangesAsync(cancellationToken);

            if (correlation.Lifetime == V1CorrelationLifetime.Singleton)
            {
                this.Logger.LogInformation("The correlation with id '{correlationId}' is a singleton and its context has been released. Disposing of it...", correlation.Id);
                await this.Mediator.ExecuteAndUnwrapAsync(new V1DeleteCorrelationCommand(correlation.Id), cancellationToken);

                this.Logger.LogInformation("The correlation with id '{correlationId}' has been successfully disposed of", correlation.Id);
            }
            this.Logger.LogInformation("Correlation outcome successfully computed");
        }
Esempio n. 3
0
        /// <inheritdoc/>
        public virtual async Task <IOperationResult> HandleAsync(V1CorrelateEventCommand command, CancellationToken cancellationToken = default)
        {
            this.Logger.LogInformation("Processing event with id '{eventId}', type '{eventType}' and source '{eventSource}'...", command.Event.Id, command.Event.Type, command.Event.Source);
            var correlations = await this.Mediator.ExecuteAndUnwrapAsync(new V1GetEventCorrelationsQuery(command.Event), cancellationToken);

            await foreach (var correlation in correlations)
            {
                this.Logger.LogInformation("Processing correlation with id '{correlationId}'...", correlation.Id);
                var matchingCondition = correlation.GetMatchingConditionFor(command.Event) !;
                var matchingFilter    = matchingCondition.GetMatchingFilterFor(command.Event) !;
                var matchingContexts  = correlation.Contexts
                                        .Where(c => c.CorrelatesTo(command.Event))
                                        .ToList();
                switch (correlation.Lifetime)
                {
                case V1CorrelationLifetime.Singleton:
                    var matchingContext = matchingContexts.FirstOrDefault();
                    if (matchingContext == null)
                    {
                        this.Logger.LogInformation("Failed to find a matching correlation context");
                        if (correlation.Contexts.Any())
                        {
                            throw new Exception("Failed to correlate event");     //should not happen
                        }
                        this.Logger.LogInformation("Creating a new correlation context...");
                        matchingContext = V1CorrelationContext.CreateFor(command.Event, matchingFilter.CorrelationMappings.Keys);
                        correlation.AddContext(matchingContext);
                        await this.Correlations.UpdateAsync(correlation, cancellationToken);

                        await this.Correlations.SaveChangesAsync(cancellationToken);

                        this.Logger.LogInformation("Correlation context with id '{contextId}' successfully created", matchingContext.Id);
                        this.Logger.LogInformation("Event successfully correlated to context with id '{contextId}'", matchingContext.Id);
                    }
                    else
                    {
                        await this.CorrelateAsync(correlation, matchingContext, command.Event, matchingFilter, cancellationToken);
                    }
                    break;

                case V1CorrelationLifetime.Transient:
                    matchingContext = matchingContexts.FirstOrDefault();
                    if (matchingContext == null)
                    {
                        this.Logger.LogInformation("Failed to find a matching correlation context");
                        this.Logger.LogInformation("Creating a new correlation context...");
                        matchingContext = V1CorrelationContext.CreateFor(command.Event, matchingFilter.CorrelationMappings.Keys);
                        correlation.AddContext(matchingContext);
                        await this.Correlations.UpdateAsync(correlation, cancellationToken);

                        await this.Correlations.SaveChangesAsync(cancellationToken);

                        this.Logger.LogInformation("Correlation context with id '{contextId}' successfully created", matchingContext.Id);
                        this.Logger.LogInformation("Event successfully correlated to context with id '{contextId}'", matchingContext.Id);
                        matchingContexts.Add(matchingContext);
                    }
                    this.Logger.LogInformation("Found {matchingContextCount} matching correlation contexts", matchingContexts.Count());
                    foreach (var context in matchingContexts)
                    {
                        await this.CorrelateAsync(correlation, context, command.Event, matchingFilter, cancellationToken);
                    }
                    break;

                default:
                    throw new NotSupportedException($"The specified {nameof(V1CorrelationLifetime)} '{correlation.Lifetime}' is not supported");
                }
            }
            return(this.Ok());
        }
 /// <summary>
 /// Initializes a new <see cref="V1CorrelateWorkflowInstanceCommand"/>
 /// </summary>
 /// <param name="id">The id of the <see cref="V1WorkflowInstance"/> to correlate</param>
 /// <param name="correlationContext">The <see cref="V1CorrelationContext"/> to correlate the <see cref="V1WorkflowInstance"/> with</param>
 public V1CorrelateWorkflowInstanceCommand(string id, V1CorrelationContext correlationContext)
 {
     this.Id = id;
     this.CorrelationContext = correlationContext;
 }