/// <inheritdoc/>
        public virtual async Task <IOperationResult <string> > HandleAsync(V1GetWorkflowInstanceLogsQuery query, CancellationToken cancellationToken = default)
        {
            var instance = await this.Repository.FindAsync(query.Id, cancellationToken);

            if (instance == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowInstance), query.Id);
            }
            if (instance.Sessions == null)
            {
                return(this.Ok(string.Empty));
            }
            var processes = new List <Integration.Models.V1WorkflowProcess>(instance.Sessions.Count);

            foreach (var processId in instance.Sessions.Select(s => s.ProcessId))
            {
                var process = await this.Processes.FindAsync(processId, cancellationToken);

                if (process == null)
                {
                    throw DomainException.NullReference(typeof(V1WorkflowProcess), processId);
                }
                processes.Add(process);
            }
            return(this.Ok(processes.Select(p => p.Logs).Aggregate((l1, l2) => l1 += l2) !));
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Integration.Models.V1WorkflowInstance> > HandleAsync(V1CorrelateWorkflowInstanceCommand command, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await this.WorkflowInstances.FindAsync(command.Id, cancellationToken);

            if (workflowInstance == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowInstance), command.Id);
            }
            workflowInstance.SetCorrelationContext(command.CorrelationContext);
            workflowInstance = await this.WorkflowInstances.UpdateAsync(workflowInstance, cancellationToken);

            await this.WorkflowInstances.SaveChangesAsync(cancellationToken);

            switch (workflowInstance.Status)
            {
            case V1WorkflowInstanceStatus.Suspended:
                await this.Mediator.ExecuteAndUnwrapAsync(new V1StartWorkflowInstanceCommand(workflowInstance.Id), cancellationToken);

                break;

            case V1WorkflowInstanceStatus.Running:
                var runtimeProxy = this.RuntimeProxyManager.GetProxy(workflowInstance.Id);
                await runtimeProxy.CorrelateAsync(command.CorrelationContext, cancellationToken);

                break;

            default:
                throw DomainException.UnexpectedState(typeof(V1WorkflowInstance), workflowInstance.Id, workflowInstance.Status);
            }
            return(this.Ok(this.Mapper.Map <Integration.Models.V1WorkflowInstance>(workflowInstance)));
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult> HandleAsync(V1DeleteWorkflowCommand command, CancellationToken cancellationToken = default)
        {
            var components = command.WorkflowId.Split(":");

            if (components.Length == 2)
            {
                var workflow = await this.WorkflowWriteModels.FindAsync(command.WorkflowId, cancellationToken);

                if (workflow == null)
                {
                    throw DomainException.NullReference(typeof(V1Workflow), command.WorkflowId);
                }
                foreach (var instanceId in this.WorkflowInstances.AsQueryable()
                         .Where(i => i.WorkflowId == workflow.Id)
                         .Select(i => i.Id)
                         .ToList())
                {
                    await this.Mediator.ExecuteAndUnwrapAsync(new V1DeleteWorkflowInstanceCommand(instanceId));
                }
                workflow.Delete();
                await this.WorkflowWriteModels.UpdateAsync(workflow, cancellationToken);

                await this.WorkflowWriteModels.RemoveAsync(workflow, cancellationToken);

                await this.WorkflowWriteModels.SaveChangesAsync(cancellationToken);
            }
            else
            {
                var workflowIds = this.WorkflowReadModels.AsQueryable()
                                  .Where(w => w.Definition.Id !.Equals(command.WorkflowId, StringComparison.OrdinalIgnoreCase))
                                  .Select(w => w.Id)
                                  .ToList();
                if (!workflowIds.Any())
                {
                    throw DomainException.NullReference(typeof(V1Workflow), command.WorkflowId);
                }
                foreach (var workflowId in workflowIds)
                {
                    var workflow = await this.WorkflowWriteModels.FindAsync(workflowId, cancellationToken);

                    if (workflow == null)
                    {
                        throw DomainException.NullReference(typeof(V1Workflow), workflowId);
                    }
                    workflow.Delete();
                    foreach (var instanceId in this.WorkflowInstances.AsQueryable()
                             .Where(i => i.WorkflowId == workflow.Id)
                             .Select(i => i.Id)
                             .ToList())
                    {
                        await this.Mediator.ExecuteAndUnwrapAsync(new V1DeleteWorkflowInstanceCommand(instanceId));
                    }
                    await this.WorkflowWriteModels.UpdateAsync(workflow, cancellationToken);

                    await this.WorkflowWriteModels.RemoveAsync(workflow, cancellationToken);
                }
                await this.WorkflowWriteModels.SaveChangesAsync(cancellationToken);
            }
            return(this.Ok());
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Integration.Models.V1WorkflowActivity> > HandleAsync(V1CreateWorkflowActivityCommand command, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await this.WorkflowInstances.FindAsync(command.WorkflowInstanceId, cancellationToken);

            if (workflowInstance == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowInstance), command.WorkflowInstanceId);
            }
            var parent = null as V1WorkflowActivity;

            if (!string.IsNullOrWhiteSpace(command.ParentId))
            {
                parent = await this.WorkflowActivities.FindAsync(command.ParentId, cancellationToken);

                if (parent == null)
                {
                    throw DomainException.NullReference(typeof(V1WorkflowActivity), command.ParentId);
                }
            }
            var activity = await this.WorkflowActivities.AddAsync(new(workflowInstance, command.Type, command.Input, command.Metadata, parent), cancellationToken);

            await this.WorkflowActivities.SaveChangesAsync(cancellationToken);

            return(this.Ok(this.Mapper.Map <Integration.Models.V1WorkflowActivity>(activity)));
        }
Beispiel #5
0
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Integration.Models.V1Event?> > HandleAsync(V1ConsumeOrBeginCorrelateEventCommand command, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await this.WorkflowInstances.FindAsync(command.WorkflowInstanceId, cancellationToken);

            if (workflowInstance == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowInstance), command.WorkflowInstanceId);
            }
            var e = workflowInstance.CorrelationContext.PendingEvents
                    .FirstOrDefault(e => e.Matches(command.EventDefinition));

            if (e == null)
            {
                var conditions = new List <V1CorrelationCondition>()
                {
                    V1CorrelationCondition.Match(command.EventDefinition)
                };
                var outcome = new V1CorrelationOutcome(V1CorrelationOutcomeType.Correlate, command.WorkflowInstanceId);
                await this.Mediator.ExecuteAndUnwrapAsync(new V1CreateCorrelationCommand(V1CorrelationLifetime.Singleton, V1CorrelationConditionType.AnyOf, conditions, outcome, workflowInstance.CorrelationContext), cancellationToken);
            }
            else
            {
                workflowInstance.CorrelationContext.RemoveEvent(e);
                await this.WorkflowInstances.UpdateAsync(workflowInstance, cancellationToken);

                await this.WorkflowInstances.SaveChangesAsync(cancellationToken);
            }
            return(this.Ok(e == null ? null : this.Mapper.Map <Integration.Models.V1Event>(e)));
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Integration.Models.V1WorkflowInstance> > HandleAsync(V1CancelWorkflowInstanceCommand command, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await this.WorkflowInstances.FindAsync(command.WorkflowInstanceId, cancellationToken);

            if (workflowInstance == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowInstance), command.WorkflowInstanceId);
            }
            if (this.RuntimeHostManager.TryGetProxy(command.WorkflowInstanceId, out var proxy))
            {
                workflowInstance.Cancel();
                workflowInstance = await this.WorkflowInstances.UpdateAsync(workflowInstance, cancellationToken);

                await this.WorkflowInstances.SaveChangesAsync(cancellationToken);

                await proxy.CancelAsync(cancellationToken);
            }
            else
            {
                workflowInstance.Cancel();
                workflowInstance.MarkAsCancelled();
                workflowInstance = await this.WorkflowInstances.UpdateAsync(workflowInstance, cancellationToken);

                await this.WorkflowInstances.SaveChangesAsync(cancellationToken);
            }
            return(this.Ok(this.Mapper.Map <Integration.Models.V1WorkflowInstance>(workflowInstance)));
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <bool> > HandleAsync(V1TryCorrelateWorkflowInstanceCommand command, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await this.WorkflowInstances.FindAsync(command.WorkflowInstanceId, cancellationToken);

            if (workflowInstance == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowInstance), command.WorkflowInstanceId);
            }
            var e = workflowInstance.CorrelationContext.PendingEvents.FirstOrDefault(e => e.Id == command.Event.Id);

            if (e == null)
            {
                if (!workflowInstance.CorrelationContext.CorrelatesTo(command.Event))
                {
                    return(this.Ok(false));
                }
                workflowInstance.CorrelationContext.Correlate(command.Event, command.MappingKeys);
            }
            else
            {
                workflowInstance.CorrelationContext.RemoveEvent(command.Event);
            }
            await this.WorkflowInstances.UpdateAsync(workflowInstance, cancellationToken);

            await this.WorkflowInstances.SaveChangesAsync(cancellationToken);

            return(this.Ok(true));
        }
Beispiel #8
0
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Stream> > HandleAsync(V1ArchiveWorkflowInstanceCommand command, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await this.WorkflowInstances.FindAsync(command.Id, cancellationToken);

            if (workflowInstance == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowInstance), command.Id);
            }
            var workflow = await this.Workflows.FindAsync(workflowInstance.WorkflowId, cancellationToken);

            if (workflow == null)
            {
                throw DomainException.NullReference(typeof(V1Workflow), workflowInstance.WorkflowId);
            }
            var directory = new DirectoryInfo(Path.Combine(Path.GetTempPath(), workflowInstance.Id));

            if (directory.Exists)
            {
                directory.Delete(true);
            }
            directory.Create();
            var buffer = await this.Serializer.SerializeAsync(workflow.Definition, cancellationToken);

            await File.WriteAllBytesAsync(Path.Combine(directory.FullName, $"definition.{this.Options.Archiving.FileExtension}"), buffer, cancellationToken);

            buffer = await this.Serializer.SerializeAsync(this.Mapper.Map <Integration.Models.V1WorkflowInstance>(workflowInstance), cancellationToken);

            await File.WriteAllBytesAsync(Path.Combine(directory.FullName, $"instance.{this.Options.Archiving.FileExtension}"), buffer, cancellationToken);

            var processesDirectory = new DirectoryInfo(Path.Combine(directory.FullName, "processes"));

            if (!processesDirectory.Exists)
            {
                processesDirectory.Create();
            }
            foreach (var processId in workflowInstance.Sessions.Select(s => s.ProcessId))
            {
                var process = await this.WorkflowProcesses.FindAsync(processId, cancellationToken);

                if (process == null)
                {
                    throw DomainException.NullReference(typeof(V1WorkflowProcess), processId);
                }
                buffer = await this.Serializer.SerializeAsync(this.Mapper.Map <Integration.Models.V1WorkflowProcess>(process), cancellationToken);

                await File.WriteAllBytesAsync(Path.Combine(processesDirectory.FullName, $"{processId}.{this.Options.Archiving.FileExtension}"), buffer, cancellationToken);
            }
            var archiveFilePath = Path.Combine(Path.GetTempPath(), $"{workflowInstance.Id}.zip");

            ZipFile.CreateFromDirectory(directory.FullName, archiveFilePath, CompressionLevel.Fastest, true);
            using var fileStream = File.OpenRead(archiveFilePath);
            var stream = new MemoryStream();
            await fileStream.CopyToAsync(stream);

            await stream.FlushAsync(cancellationToken);

            stream.Position = 0;
            return(this.Ok(stream));
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <TEntity> > HandleAsync(V1FindByIdQuery <TEntity, TKey> query, CancellationToken cancellationToken = default)
        {
            var entity = await this.Repository.FindAsync(query.Id, cancellationToken);

            if (entity == null)
            {
                throw DomainException.NullReference(typeof(TEntity), query.Id, nameof(query.Id));
            }
            return(this.Ok(entity));
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Integration.Models.V1WorkflowInstance> > HandleAsync(V1MarkWorkflowInstanceAsCancelledCommand command, CancellationToken cancellationToken = default)
        {
            var instance = await this.WorkflowInstances.FindAsync(command.Id, cancellationToken);

            if (instance == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowInstance), command.Id);
            }
            instance.MarkAsCancelled();
            instance = await this.WorkflowInstances.UpdateAsync(instance, cancellationToken);

            await this.WorkflowInstances.SaveChangesAsync(cancellationToken);

            return(this.Ok(this.Mapper.Map <Integration.Models.V1WorkflowInstance>(instance)));
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Integration.Models.V1WorkflowInstance> > HandleAsync(V1SetWorkflowInstanceCorrelationMappingCommand command, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await this.WorkflowInstances.FindAsync(command.Id, cancellationToken);

            if (workflowInstance == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowInstance), command.Id);
            }
            workflowInstance.SetCorrelationMapping(command.Key, command.Value);
            workflowInstance = await this.WorkflowInstances.UpdateAsync(workflowInstance, cancellationToken);

            await this.WorkflowInstances.SaveChangesAsync(cancellationToken);

            return(this.Ok(this.Mapper.Map <Integration.Models.V1WorkflowInstance>(workflowInstance)));
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Integration.Models.V1WorkflowActivity> > HandleAsync(V1CancelWorkflowActivityCommand command, CancellationToken cancellationToken = default)
        {
            var activity = await this.Activities.FindAsync(command.Id, cancellationToken);

            if (activity == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowActivity), command.Id);
            }
            activity.Cancel();
            activity = await this.Activities.UpdateAsync(activity, cancellationToken);

            await this.Activities.SaveChangesAsync(cancellationToken);

            return(this.Ok(this.Mapper.Map <Integration.Models.V1WorkflowActivity>(activity)));
        }
Beispiel #13
0
        /// <inheritdoc/>
        public virtual async Task <IOperationResult> HandleAsync(V1DeleteCorrelationCommand command, CancellationToken cancellationToken = default)
        {
            var correlation = await this.Correlations.FindAsync(command.Id, cancellationToken);

            if (correlation == null)
            {
                throw DomainException.NullReference(typeof(V1Correlation), command.Id);
            }
            correlation.Delete();
            await this.Correlations.UpdateAsync(correlation, cancellationToken);

            await this.Correlations.RemoveAsync(correlation, cancellationToken);

            await this.Correlations.SaveChangesAsync(cancellationToken);

            return(this.Ok());
        }
Beispiel #14
0
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Integration.Models.V1WorkflowInstance> > HandleAsync(V1ResumeWorkflowInstanceCommand command, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await this.WorkflowInstances.FindAsync(command.WorkflowInstanceId, cancellationToken);

            if (workflowInstance == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowInstance), command.WorkflowInstanceId);
            }
            var process = await this.ProcessManager.StartProcessAsync(workflowInstance, cancellationToken);

            workflowInstance.Resume(process.Id);
            workflowInstance = await this.WorkflowInstances.UpdateAsync(workflowInstance, cancellationToken);

            await this.WorkflowInstances.SaveChangesAsync(cancellationToken);

            return(this.Ok(this.Mapper.Map <Integration.Models.V1WorkflowInstance>(workflowInstance)));
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Dynamic> > HandleAsync(V1GetActivityParentStateDataQuery query, CancellationToken cancellationToken = default)
        {
            var activity = await this.Repository.FindAsync(query.ActivityId, cancellationToken);

            if (activity == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowActivity), query.ActivityId);
            }
            while (activity != null)
            {
                if (activity.Type == V1WorkflowActivityType.State)
                {
                    return(this.Ok(activity.Input));
                }
                activity = await this.Repository.FindAsync(activity.ParentId, cancellationToken);
            }
            return(this.Ok());
        }
Beispiel #16
0
        /// <inheritdoc/>
        public virtual async Task <IOperationResult> HandleAsync(V1ScheduleWorkflowCommand command, CancellationToken cancellationToken = default)
        {
            var workflow = await this.Workflows.FindAsync(command.WorkflowId, cancellationToken);

            if (workflow == null)
            {
                throw DomainException.NullReference(typeof(V1Workflow), command.WorkflowId);
            }
            var rawCronExpression = workflow.Definition.Start !.Schedule !.CronExpression;

            if (workflow.Definition.Start.Schedule.Cron == null)
            {
                throw new DomainException($"The schedule's '{nameof(ScheduleDefinition.CronExpression)}' or '{nameof(ScheduleDefinition.Cron)}' property of the specified workflow must be set in order to be scheduled");
            }
            if (string.IsNullOrWhiteSpace(rawCronExpression))
            {
                rawCronExpression = workflow.Definition.Start !.Schedule !.Cron.Expression;
            }
            var cronExpression = CronExpression.Parse(rawCronExpression);
            var timeZone       = TimeZoneInfo.Local;

            if (!string.IsNullOrWhiteSpace(workflow.Definition.Start.Schedule.Timezone))
            {
                timeZone = TimeZoneInfo.FindSystemTimeZoneById(workflow.Definition.Start.Schedule.Timezone);
            }
            Func <IServiceProvider, Task> job = async provider =>
            {
                var mediator = provider.GetRequiredService <IMediator>();
                await mediator.ExecuteAndUnwrapAsync(new V1CreateWorkflowInstanceCommand(workflow.Id, V1WorkflowInstanceActivationType.Cron, new(), null, true, null));
            };

            if (command.CatchUpMissedOccurences &&
                workflow.LastInstanciated.HasValue)
            {
                foreach (var occurence in cronExpression.GetOccurrences(workflow.LastInstanciated.Value.DateTime, DateTime.Now, timeZone))
                {
                    await this.Mediator.ExecuteAndUnwrapAsync(new V1CreateWorkflowInstanceCommand(workflow.Id, V1WorkflowInstanceActivationType.Cron, new(), null, true, null), cancellationToken);
                }
            }
            await this.CronJobScheduler.ScheduleJobAsync(workflow.Definition.Id !, cronExpression, timeZone, job, workflow.Definition.Start.Schedule.Cron?.ValidUntil, cancellationToken);

            return(this.Ok());
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult> HandleAsync(V1DeleteCommand <TAggregate, TKey> command, CancellationToken cancellationToken = default)
        {
            if (!await this.Repository.ContainsAsync(command.Id, cancellationToken))
            {
                throw DomainException.NullReference(typeof(TAggregate), command.Id);
            }
            var aggregate = await this.Repository.FindAsync(command.Id, cancellationToken);

            if (aggregate == null)
            {
                throw DomainException.NullReference(typeof(TAggregate), command.Id);
            }
            aggregate.Delete();
            await this.Repository.UpdateAsync(aggregate, cancellationToken);

            await this.Repository.RemoveAsync(aggregate, cancellationToken);

            await this.Repository.SaveChangesAsync(cancellationToken);

            return(this.Ok());
        }
 /// <inheritdoc/>
 public virtual async Task <IOperationResult <Integration.Models.V1Workflow> > HandleAsync(V1GetWorkflowByIdQuery query, CancellationToken cancellationToken = default)
 {
     Integration.Models.V1Workflow?workflow;
     if (string.IsNullOrWhiteSpace(query.Version) ||
         query.Version == "latest")
     {
         workflow = this.Repository.AsQueryable()
                    .Where(wf => wf.Definition.Id !.Equals(query.Id, StringComparison.OrdinalIgnoreCase))
                    .OrderByDescending(wf => wf.Definition.Version)
                    .FirstOrDefault() !;
     }
     else
     {
         workflow = await this.Repository.FindAsync($"{query.Id}:{query.Version}", cancellationToken);
     }
     if (workflow == null)
     {
         throw DomainException.NullReference(typeof(V1Workflow), query.Id);
     }
     return(this.Ok(workflow));
 }
Beispiel #19
0
        /// <inheritdoc/>
        public virtual async Task <IOperationResult> HandleAsync(V1DeleteWorkflowInstanceCommand command, CancellationToken cancellationToken = default)
        {
            var workflowInstance = await this.WorkflowInstances.FindAsync(command.WorkflowInstanceId, cancellationToken);

            if (workflowInstance == null)
            {
                throw DomainException.NullReference(typeof(V1WorkflowInstance), command.WorkflowInstanceId);
            }
            if (this.RuntimeProxyManager.TryGetProxy(command.WorkflowInstanceId, out var proxy))
            {
                await proxy.CancelAsync(cancellationToken);

                this.RuntimeProxyManager.Unregister(proxy);
            }
            workflowInstance.Delete();
            await this.WorkflowInstances.UpdateAsync(workflowInstance, cancellationToken);

            await this.WorkflowInstances.RemoveAsync(workflowInstance, cancellationToken);

            await this.WorkflowInstances.SaveChangesAsync(cancellationToken);

            return(this.Ok());
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Integration.Models.V1Workflow> > HandleAsync(V1CreateWorkflowCommand command, CancellationToken cancellationToken = default)
        {
            var validationResult = await this.WorkflowValidator.ValidateAsync(command.Definition, true, true, cancellationToken);

            if (!validationResult.IsValid)
            {
                return(this.Invalid(validationResult.AsErrors().ToArray()));
            }
            foreach (var subflowRef in command.Definition.GetSubflowReferences())
            {
                var reference = subflowRef.WorkflowId;
                if (!string.IsNullOrWhiteSpace(subflowRef.Version))
                {
                    reference += $":{subflowRef.Version}";
                }
                var subflow = await this.Mediator.ExecuteAndUnwrapAsync(new V1GetWorkflowByIdQuery(subflowRef.WorkflowId, subflowRef.Version), cancellationToken);

                if (subflow == null)
                {
                    throw DomainException.NullReference(typeof(V1Workflow), $"Failed to find the referenced workflow '{reference}'");
                }
            }
            if (command.IfNotExists &&
                await this.Workflows.ContainsAsync(command.Definition.GetUniqueIdentifier(), cancellationToken))
            {
                return(this.NotModified());
            }
            else
            {
                while (await this.Workflows.ContainsAsync(command.Definition.GetUniqueIdentifier(), cancellationToken))
                {
                    var version = Version.Parse(command.Definition.Version);
                    version = new Version(version.Major, version.Minor, version.Build == -1 ? 1 : version.Build + 1);
                    command.Definition.Version = version.ToString(3);
                }
            }
            var workflow = await this.Workflows.AddAsync(new(command.Definition), cancellationToken);

            await this.Workflows.SaveChangesAsync(cancellationToken);

            var startState = workflow.Definition.GetStartState();

            if (startState is EventStateDefinition eventState)
            {
                var lifetime      = V1CorrelationLifetime.Transient;
                var conditionType = eventState.Exclusive ? V1CorrelationConditionType.AnyOf : V1CorrelationConditionType.AllOf;
                var conditions    = new List <V1CorrelationCondition>();
                foreach (var trigger in eventState.Triggers)
                {
                    var filters = new List <V1EventFilter>(trigger.Events.Count);
                    foreach (var eventRef in trigger.Events)
                    {
                        if (!workflow.Definition.TryGetEvent(eventRef, out var e))
                        {
                            throw DomainException.NullReference(typeof(EventDefinition), eventRef, nameof(EventDefinition.Name));
                        }
                        filters.Add(V1EventFilter.Match(e));
                    }
                    conditions.Add(new(filters.ToArray()));
                }
                var outcome = new V1CorrelationOutcome(V1CorrelationOutcomeType.Start, workflow.Id);
                await this.Mediator.ExecuteAndUnwrapAsync(new V1CreateCorrelationCommand(lifetime, conditionType, conditions, outcome, null));
            }
            else if (!string.IsNullOrWhiteSpace(workflow.Definition.Start?.Schedule?.Cron?.Expression))
            {
                await this.Mediator.ExecuteAndUnwrapAsync(new V1ScheduleWorkflowCommand(workflow.Id, false), cancellationToken);
            }
            return(this.Ok(this.Mapper.Map <Integration.Models.V1Workflow>(workflow)));
        }
        /// <inheritdoc/>
        public virtual async Task <IOperationResult <Integration.Models.V1WorkflowInstance> > HandleAsync(V1CreateWorkflowInstanceCommand command, CancellationToken cancellationToken = default)
        {
            var workflow = await this.Workflows.FindAsync(command.WorkflowId, cancellationToken);

            if (workflow == null)
            {
                throw DomainException.NullReference(typeof(V1Workflow), command.WorkflowId);
            }
            var parent = null as V1WorkflowInstance;

            if (!string.IsNullOrWhiteSpace(command.ParentId))
            {
                parent = await this.WorkflowInstances.FindAsync(command.ParentId, cancellationToken);

                if (parent == null)
                {
                    throw DomainException.NullReference(typeof(V1WorkflowInstance), command.ParentId);
                }
            }
            string?key             = null;
            var    dataInputSchema = workflow.Definition.DataInputSchema?.Schema;

            if (dataInputSchema == null &&
                workflow.Definition.DataInputSchemaUri != null)
            {
                using var httpClient = this.HttpClientFactory.CreateClient();
                var json = await httpClient.GetStringAsync(workflow.Definition.DataInputSchemaUri, cancellationToken);

                dataInputSchema = JSchema.Parse(json);
            }
            if (dataInputSchema != null)
            {
                var     input = command.InputData;
                JObject?jobj;
                if (input == null)
                {
                    jobj = new JObject();
                }
                else
                {
                    jobj = JObject.FromObject(input);
                }
                if (!jobj.IsValid(dataInputSchema, out IList <string> errors))
                {
                    throw new DomainArgumentException($"Invalid workflow input data:{Environment.NewLine}{string.Join(Environment.NewLine, errors)}", nameof(command.InputData));
                }
            }
            if (!string.IsNullOrWhiteSpace(workflow.Definition.Key) &&
                command.InputData != null)
            {
                try
                {
                    key = this.ExpressionEvaluatorProvider.GetEvaluator(workflow.Definition.ExpressionLanguage) !.Evaluate(workflow.Definition.Key, command.InputData)?.ToString();
                }
                catch { }
            }
            if (string.IsNullOrWhiteSpace(key))
            {
                key = Guid.NewGuid().ToBase64();
            }
            while (await this.WorkflowInstances.ContainsAsync(V1WorkflowInstance.BuildUniqueIdentifier(key, workflow), cancellationToken))
            {
                key = Guid.NewGuid().ToBase64();
            }
            var workflowInstance = await this.WorkflowInstances.AddAsync(new(key.ToLowerInvariant(), workflow, command.ActivationType, command.InputData, command.CorrelationContext, parent), cancellationToken);

            await this.WorkflowInstances.SaveChangesAsync(cancellationToken);

            workflow.Instanciate();
            await this.Workflows.UpdateAsync(workflow, cancellationToken);

            await this.Workflows.SaveChangesAsync(cancellationToken);

            if (command.AutoStart)
            {
                await this.Mediator.ExecuteAndUnwrapAsync(new V1StartWorkflowInstanceCommand(workflowInstance.Id), cancellationToken);
            }
            return(this.Ok(this.Mapper.Map <Integration.Models.V1WorkflowInstance>(workflowInstance)));
        }