public async Task Execute(WorkflowInstance workflow, IPersistenceProvider persistenceStore, WorkflowOptions options)
        {
            //TODO: split this method up
            List <ExecutionPointer> exePointers = new List <ExecutionPointer>(workflow.ExecutionPointers.Where(x => x.Active && (!x.SleepUntil.HasValue || x.SleepUntil < DateTime.Now.ToUniversalTime())));
            var def = _registry.GetDefinition(workflow.WorkflowDefinitionId, workflow.Version);

            if (def == null)
            {
                _logger.LogError("Workflow {0} version {1} is not registered", workflow.WorkflowDefinitionId, workflow.Version);
                return;
            }

            foreach (var pointer in exePointers)
            {
                var step = def.Steps.First(x => x.Id == pointer.StepId);
                if (step != null)
                {
                    try
                    {
                        if (step.InitForExecution(_host, persistenceStore, def, workflow, pointer) == ExecutionPipelineDirective.Defer)
                        {
                            continue;
                        }

                        if (!pointer.StartTime.HasValue)
                        {
                            pointer.StartTime = DateTime.Now;
                        }

                        _logger.LogDebug("Starting step {0} on workflow {1}", step.Name, workflow.Id);

                        IStepBody body;

                        if (step is WorkflowStepInline)
                        {
                            body = new InlineStepBody((step as WorkflowStepInline).Body);
                        }
                        else
                        {
                            body = (_serviceProvider.GetService(step.BodyType) as IStepBody);
                            if (body == null)
                            {
                                var stepCtor = step.BodyType.GetConstructor(new Type[] { });
                                if (stepCtor != null)
                                {
                                    body = (stepCtor.Invoke(null) as IStepBody);
                                }
                            }

                            if (body == null)
                            {
                                _logger.LogError("Unable to construct step body {0}", step.BodyType.ToString());
                                pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(options.ErrorRetryInterval);
                                pointer.Errors.Add(new ExecutionError()
                                {
                                    Id        = Guid.NewGuid().ToString(),
                                    ErrorTime = DateTime.Now.ToUniversalTime(),
                                    Message   = String.Format("Unable to construct step body {0}", step.BodyType.ToString())
                                });
                                continue;
                            }
                        }

                        foreach (var input in step.Inputs)
                        {
                            var member        = (input.Target.Body as MemberExpression);
                            var resolvedValue = input.Source.Compile().DynamicInvoke(workflow.Data);
                            step.BodyType.GetProperty(member.Member.Name).SetValue(body, resolvedValue);
                        }

                        IStepExecutionContext context = new StepExecutionContext()
                        {
                            Workflow        = workflow,
                            Step            = step,
                            PersistenceData = pointer.PersistenceData
                        };

                        if (step.BeforeExecute(_host, persistenceStore, context, pointer, body) == ExecutionPipelineDirective.Defer)
                        {
                            continue;
                        }

                        var result = body.Run(context);

                        foreach (var output in step.Outputs)
                        {
                            var member        = (output.Target.Body as MemberExpression);
                            var resolvedValue = output.Source.Compile().DynamicInvoke(body);
                            var data          = workflow.Data;
                            data.GetType().GetProperty(member.Member.Name).SetValue(data, resolvedValue);
                        }

                        if (result.Proceed)
                        {
                            pointer.Active  = false;
                            pointer.EndTime = DateTime.Now;
                            int  forkCounter = 1;
                            bool noOutcomes  = true;
                            foreach (var outcome in step.Outcomes.Where(x => object.Equals(x.Value, result.OutcomeValue)))
                            {
                                workflow.ExecutionPointers.Add(new ExecutionPointer()
                                {
                                    Id             = Guid.NewGuid().ToString(),
                                    StepId         = outcome.NextStep,
                                    Active         = true,
                                    ConcurrentFork = (forkCounter * pointer.ConcurrentFork),
                                    StepName       = def.Steps.First(x => x.Id == outcome.NextStep).Name
                                });
                                noOutcomes = false;
                                forkCounter++;
                            }
                            pointer.PathTerminator = noOutcomes;
                        }
                        else
                        {
                            pointer.PersistenceData = result.PersistenceData;
                            if (result.SleepFor.HasValue)
                            {
                                pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(result.SleepFor.Value);
                            }
                        }

                        step.AfterExecute(_host, persistenceStore, context, result, pointer);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError("Workflow {0} raised error on step {1} Message: {2}", workflow.Id, pointer.StepId, ex.Message);
                        pointer.Errors.Add(new ExecutionError()
                        {
                            Id        = Guid.NewGuid().ToString(),
                            ErrorTime = DateTime.Now.ToUniversalTime(),
                            Message   = ex.Message
                        });

                        switch (step.ErrorBehavior ?? def.DefaultErrorBehavior)
                        {
                        case WorkflowErrorHandling.Retry:
                            pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(step.RetryInterval ?? def.DefaultErrorRetryInterval ?? options.ErrorRetryInterval);
                            break;

                        case WorkflowErrorHandling.Suspend:
                            workflow.Status = WorkflowStatus.Suspended;
                            break;

                        case WorkflowErrorHandling.Terminate:
                            workflow.Status = WorkflowStatus.Terminated;
                            break;
                        }

                        _host.ReportStepError(workflow, step, ex);
                    }

                    await persistenceStore.PersistWorkflow(workflow);
                }
                else
                {
                    _logger.LogError("Unable to find step {0} in workflow definition", pointer.StepId);
                    pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(options.ErrorRetryInterval);
                    pointer.Errors.Add(new ExecutionError()
                    {
                        ErrorTime = DateTime.Now.ToUniversalTime(),
                        Message   = String.Format("Unable to find step {0} in workflow definition", pointer.StepId)
                    });
                }
            }
            DetermineNextExecutionTime(workflow);
            await persistenceStore.PersistWorkflow(workflow);
        }
Example #2
0
        public async Task Execute(WorkflowInstance workflow, IPersistenceProvider persistenceStore, WorkflowOptions options)
        {
            List <ExecutionPointer> exePointers = new List <ExecutionPointer>(workflow.ExecutionPointers.Where(x => x.Active && (!x.SleepUntil.HasValue || x.SleepUntil < DateTime.Now.ToUniversalTime())));
            var def = _registry.GetDefinition(workflow.WorkflowDefinitionId, workflow.Version);

            if (def == null)
            {
                _logger.LogError("Workflow {0} version {1} is not registered", workflow.WorkflowDefinitionId, workflow.Version);
                return;
            }

            foreach (var pointer in exePointers)
            {
                var step = def.Steps.First(x => x.Id == pointer.StepId);
                if (step != null)
                {
                    try
                    {
                        if ((step is ISubscriptionStep) && (!pointer.EventPublished))
                        {
                            pointer.EventKey  = (step as ISubscriptionStep).EventKey;
                            pointer.EventName = (step as ISubscriptionStep).EventName;
                            pointer.Active    = false;
                            await persistenceStore.PersistWorkflow(workflow);

                            await _host.SubscribeEvent(workflow.Id, pointer.StepId, pointer.EventName, pointer.EventKey);

                            continue;
                        }

                        if (!pointer.StartTime.HasValue)
                        {
                            pointer.StartTime = DateTime.Now;
                        }

                        _logger.LogDebug("Starting step {0} on workflow {1}", step.Name, workflow.Id);

                        IStepBody body;

                        if (step is WorkflowStepInline)
                        {
                            body = new InlineStepBody((step as WorkflowStepInline).Body);
                        }
                        else
                        {
                            body = (_serviceProvider.GetService(step.BodyType) as IStepBody);
                            if (body == null)
                            {
                                var stepCtor = step.BodyType.GetConstructor(new Type[] { });
                                if (stepCtor != null)
                                {
                                    body = (stepCtor.Invoke(null) as IStepBody);
                                }
                            }

                            if (body == null)
                            {
                                _logger.LogError("Unable to construct step body {0}", step.BodyType.ToString());
                                pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(options.ErrorRetryInterval);
                                pointer.Errors.Add(new ExecutionError()
                                {
                                    ErrorTime = DateTime.Now.ToUniversalTime(),
                                    Message   = String.Format("Unable to construct step body {0}", step.BodyType.ToString())
                                });
                                continue;
                            }
                        }

                        foreach (var input in step.Inputs)
                        {
                            var member        = (input.Target.Body as MemberExpression);
                            var resolvedValue = input.Source.Compile().DynamicInvoke(workflow.Data);
                            step.BodyType.GetProperty(member.Member.Name).SetValue(body, resolvedValue);
                        }

                        if ((body is ISubscriptionBody) && (pointer.EventPublished))
                        {
                            (body as ISubscriptionBody).EventData = pointer.EventData;
                        }

                        IStepExecutionContext context = new StepExecutionContext()
                        {
                            Workflow        = workflow,
                            Step            = step,
                            PersistenceData = pointer.PersistenceData
                        };

                        var result = body.Run(context);

                        foreach (var output in step.Outputs)
                        {
                            var member        = (output.Target.Body as MemberExpression);
                            var resolvedValue = output.Source.Compile().DynamicInvoke(body);
                            var data          = workflow.Data;
                            data.GetType().GetProperty(member.Member.Name).SetValue(data, resolvedValue);
                        }

                        if (result.Proceed)
                        {
                            pointer.Active  = false;
                            pointer.EndTime = DateTime.Now;

                            foreach (var outcome in step.Outcomes.Where(x => object.Equals(x.Value, result.OutcomeValue)))
                            {
                                workflow.ExecutionPointers.Add(new ExecutionPointer()
                                {
                                    StepId = outcome.NextStep,
                                    Active = true
                                });
                            }
                        }
                        else
                        {
                            pointer.PersistenceData = result.PersistenceData;
                            if (result.SleepFor.HasValue)
                            {
                                pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(result.SleepFor.Value);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError("Workflow {0} raised error on step {1} Message: {2}", workflow.Id, pointer.StepId, ex.Message);
                        pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(options.ErrorRetryInterval);
                        pointer.Errors.Add(new ExecutionError()
                        {
                            ErrorTime = DateTime.Now.ToUniversalTime(),
                            Message   = ex.Message
                        });
                    }

                    await persistenceStore.PersistWorkflow(workflow);
                }
                else
                {
                    _logger.LogError("Unable to find step {0} in workflow definition", pointer.StepId);
                    pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(options.ErrorRetryInterval);
                    pointer.Errors.Add(new ExecutionError()
                    {
                        ErrorTime = DateTime.Now.ToUniversalTime(),
                        Message   = String.Format("Unable to find step {0} in workflow definition", pointer.StepId)
                    });
                }
            }
            DetermineNextExecutionTime(workflow);
            await persistenceStore.PersistWorkflow(workflow);
        }