Ejemplo n.º 1
0
        public void HandleStepException(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step, Exception exception)
        {
            _eventPublisher.PublishNotification(new WorkflowError
            {
                EventTimeUtc         = _datetimeProvider.UtcNow,
                Reference            = workflow.Reference,
                WorkflowInstanceId   = workflow.Id,
                WorkflowDefinitionId = workflow.WorkflowDefinitionId,
                Version            = workflow.Version,
                ExecutionPointerId = pointer.Id,
                StepId             = step.Id,
                Message            = exception.Message
            });
            pointer.Status = PointerStatus.Failed;

            var queue = new Queue <ExecutionPointer>();

            queue.Enqueue(pointer);

            while (queue.Count > 0)
            {
                var exceptionPointer = queue.Dequeue();
                var exceptionStep    = def.Steps.FindById(exceptionPointer.StepId);
                var shouldCompensate = ShouldCompensate(workflow, def, exceptionPointer);
                var errorOption      = (exceptionStep.ErrorBehavior ?? (shouldCompensate ? WorkflowErrorHandling.Compensate : def.DefaultErrorBehavior));

                foreach (var handler in _errorHandlers.Where(x => x.Type == errorOption))
                {
                    handler.Handle(workflow, def, exceptionPointer, exceptionStep, exception, queue);
                }
            }
        }
Ejemplo n.º 2
0
        private bool ShouldCompensate(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer currentPointer)
        {
            var scope = new Stack <string>(currentPointer.Scope);

            scope.Push(currentPointer.Id);

            while (scope.Count > 0)
            {
                var pointerId = scope.Pop();
                var pointer   = workflow.ExecutionPointers.FindById(pointerId);
                var step      = def.Steps.FindById(pointer.StepId);
                if ((step.CompensationStepId.HasValue) || (step.RevertChildrenAfterCompensation))
                {
                    return(true);
                }
            }

            return(false);
        }
Ejemplo n.º 3
0
        private bool InitializeStep(WorkflowInstance workflow, WorkflowStep step, WorkflowExecutorResult wfResult, WorkflowDefinition def, ExecutionPointer pointer)
        {
            switch (step.InitForExecution(wfResult, def, workflow, pointer))
            {
            case ExecutionPipelineDirective.Defer:
                return(false);

            case ExecutionPipelineDirective.EndWorkflow:
                workflow.Status       = WorkflowStatus.Complete;
                workflow.CompleteTime = _datetimeProvider.UtcNow;
                return(false);
            }

            if (pointer.Status != PointerStatus.Running)
            {
                pointer.Status = PointerStatus.Running;
                _publisher.PublishNotification(new StepStarted
                {
                    EventTimeUtc         = _datetimeProvider.UtcNow,
                    Reference            = workflow.Reference,
                    ExecutionPointerId   = pointer.Id,
                    StepId               = step.Id,
                    WorkflowInstanceId   = workflow.Id,
                    WorkflowDefinitionId = workflow.WorkflowDefinitionId,
                    Version              = workflow.Version
                });
            }

            if (!pointer.StartTime.HasValue)
            {
                pointer.StartTime = _datetimeProvider.UtcNow;
            }

            return(true);
        }
        private async Task ExecuteStep(WorkflowInstance workflow, WorkflowStep step, ExecutionPointer pointer, WorkflowExecutorResult wfResult, WorkflowDefinition def)
        {
            using (var scope = _scopeProvider.CreateScope())
            {
                _logger.LogDebug("Starting step {0} on workflow {1}", step.Name, workflow.Id);

                IStepBody body = step.ConstructBody(scope.ServiceProvider);

                if (body == null)
                {
                    _logger.LogError("Unable to construct step body {0}", step.BodyType.ToString());
                    pointer.SleepUntil = _datetimeProvider.Now.ToUniversalTime().Add(_options.ErrorRetryInterval);
                    wfResult.Errors.Add(new ExecutionError()
                    {
                        WorkflowId         = workflow.Id,
                        ExecutionPointerId = pointer.Id,
                        ErrorTime          = _datetimeProvider.Now.ToUniversalTime(),
                        Message            = $"Unable to construct step body {step.BodyType.ToString()}"
                    });
                    return;
                }

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

                foreach (var input in step.Inputs)
                {
                    input.AssignInput(workflow.Data, body, context);
                }

                switch (step.BeforeExecute(wfResult, context, pointer, body))
                {
                case ExecutionPipelineDirective.Defer:
                    return;

                case ExecutionPipelineDirective.EndWorkflow:
                    workflow.Status       = WorkflowStatus.Complete;
                    workflow.CompleteTime = _datetimeProvider.Now.ToUniversalTime();
                    await _workflowController.PublishEvent("WorkFlowEnded", workflow.Id, null);

                    return;
                }

                var result = await body.RunAsync(context);

                if (result.Proceed)
                {
                    foreach (var output in step.Outputs)
                    {
                        output.AssignOutput(workflow.Data, body, context);
                    }
                }

                _executionResultProcessor.ProcessExecutionResult(workflow, def, pointer, step, result, wfResult);
                step.AfterExecute(wfResult, context, result, pointer);
            }
        }
        private int?FindScopeCompensationStepId(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer currentPointer)
        {
            var scope = new Stack <string>(currentPointer.Scope);

            scope.Push(currentPointer.Id);

            while (scope.Count > 0)
            {
                var pointerId = scope.Pop();
                var pointer   = workflow.ExecutionPointers.First(x => x.Id == pointerId);
                var step      = def.Steps.First(x => x.Id == pointer.StepId);
                if (step.CompensationStepId.HasValue)
                {
                    return(step.CompensationStepId.Value);
                }
            }

            return(null);
        }
        public void HandleStepException(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step)
        {
            pointer.Status = PointerStatus.Failed;
            var compensatingStepId = FindScopeCompensationStepId(workflow, def, pointer);
            var errorOption        = (step.ErrorBehavior ?? (compensatingStepId.HasValue ? WorkflowErrorHandling.Compensate : def.DefaultErrorBehavior));

            SelectErrorStrategy(errorOption, workflow, def, pointer, step);
        }
 public void Handle(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step, Exception exception, Queue <ExecutionPointer> bubbleUpQueue)
 {
     pointer.RetryCount++;
     pointer.SleepUntil = _datetimeProvider.Now.ToUniversalTime().Add(step.RetryInterval ?? def.DefaultErrorRetryInterval ?? _options.ErrorRetryInterval);
     step.PrimeForRetry(pointer);
 }
 public override ExecutionPipelineDirective BeforeExecute(WorkflowExecutorResult executorResult, IStepExecutionContext context, ExecutionPointer executionPointer, IStepBody body)
 {
     if (executionPointer.EventPublished)
     {
         if ((body is UserStep) && (executionPointer.EventData is UserAction))
         {
             (body as UserStep).UserAction = (executionPointer.EventData as UserAction);
             executionPointer.ExtensionAttributes["ActionUser"] = (executionPointer.EventData as UserAction).User;
         }
     }
     return(ExecutionPipelineDirective.Next);
 }
Ejemplo n.º 9
0
 public override ExecutionPipelineDirective BeforeExecute(WorkflowExecutorResult executorResult, IStepExecutionContext context, ExecutionPointer executionPointer, IStepBody body)
 {
     if (executionPointer.EventPublished)
     {
         if (body is ISubscriptionBody)
         {
             (body as ISubscriptionBody).EventData = executionPointer.EventData;
         }
     }
     return(ExecutionPipelineDirective.Next);
 }
Ejemplo n.º 10
0
        public override void AfterWorkflowIteration(WorkflowExecutorResult executorResult, WorkflowDefinition defintion, WorkflowInstance workflow, ExecutionPointer executionPointer)
        {
            base.AfterWorkflowIteration(executorResult, defintion, workflow, executionPointer);
            var taskStep = workflow.ExecutionPointers.Find(x => x.Id == executionPointer.PredecessorId);

            if (taskStep.EventPublished)
            {
                executionPointer.EndTime = DateTime.Now.ToUniversalTime();
                executionPointer.Active  = false;
            }
        }
Ejemplo n.º 11
0
        public override ExecutionPipelineDirective InitForExecution(WorkflowExecutorResult executorResult, WorkflowDefinition defintion, WorkflowInstance workflow, ExecutionPointer executionPointer)
        {
            if (!executionPointer.EventPublished)
            {
                if (EventKey != null)
                {
                    executionPointer.EventKey = Convert.ToString(EventKey.Compile().DynamicInvoke(workflow.Data));
                }

                DateTime effectiveDate = DateTime.MinValue;

                if (EffectiveDate != null)
                {
                    effectiveDate = Convert.ToDateTime(EffectiveDate.Compile().DynamicInvoke(workflow.Data));
                }

                effectiveDate = effectiveDate.ToUniversalTime();

                executionPointer.EventName = EventName;
                executionPointer.Active    = false;

                executorResult.Subscriptions.Add(new EventSubscription()
                {
                    WorkflowId    = workflow.Id,
                    StepId        = executionPointer.StepId,
                    EventName     = executionPointer.EventName,
                    EventKey      = executionPointer.EventKey,
                    SubscribeAsOf = effectiveDate
                });

                return(ExecutionPipelineDirective.Defer);
            }
            return(ExecutionPipelineDirective.Next);
        }
Ejemplo n.º 12
0
 public override ExecutionPipelineDirective InitForExecution(WorkflowExecutorResult executorResult, WorkflowDefinition defintion, WorkflowInstance workflow, ExecutionPointer executionPointer)
 {
     return(ExecutionPipelineDirective.EndWorkflow);
 }
        public ExecutionPointer BuildCompensationPointer(WorkflowDefinition def, ExecutionPointer pointer, ExecutionPointer exceptionPointer, int compensationStepId)
        {
            var nextId = GenerateId();

            return(new ExecutionPointer()
            {
                Id = nextId,
                PredecessorId = exceptionPointer.Id,
                StepId = compensationStepId,
                Active = true,
                ContextItem = pointer.ContextItem,
                Status = PointerStatus.Pending,
                StepName = def.Steps.First(x => x.Id == compensationStepId).Name,
                Scope = new Stack <string>(pointer.Scope)
            });
        }
Ejemplo n.º 14
0
        public void ProcessExecutionResult(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step, ExecutionResult result, WorkflowExecutorResult workflowResult)
        {
            pointer.PersistenceData = result.PersistenceData;
            pointer.Outcome         = result.OutcomeValue;
            if (result.SleepFor.HasValue)
            {
                pointer.SleepUntil = _datetimeProvider.UtcNow.Add(result.SleepFor.Value);
                pointer.Status     = PointerStatus.Sleeping;
            }

            if (!string.IsNullOrEmpty(result.EventName))
            {
                pointer.EventName = result.EventName;
                pointer.EventKey  = result.EventKey;
                pointer.Active    = false;
                pointer.Status    = PointerStatus.WaitingForEvent;

                workflowResult.Subscriptions.Add(new EventSubscription
                {
                    WorkflowId         = workflow.Id,
                    StepId             = pointer.StepId,
                    ExecutionPointerId = pointer.Id,
                    EventName          = pointer.EventName,
                    EventKey           = pointer.EventKey,
                    SubscribeAsOf      = result.EventAsOf,
                    SubscriptionData   = result.SubscriptionData
                });
            }

            if (result.Proceed)
            {
                pointer.Active  = false;
                pointer.EndTime = _datetimeProvider.UtcNow;
                pointer.Status  = PointerStatus.Complete;

                foreach (var outcomeTarget in step.Outcomes.Where(x => x.Matches(result, workflow.Data)))
                {
                    workflow.ExecutionPointers.Add(_pointerFactory.BuildNextPointer(def, pointer, outcomeTarget));
                }

                var pendingSubsequents = workflow.ExecutionPointers
                                         .FindByStatus(PointerStatus.PendingPredecessor)
                                         .Where(x => x.PredecessorId == pointer.Id);

                foreach (var subsequent in pendingSubsequents)
                {
                    subsequent.Status = PointerStatus.Pending;
                    subsequent.Active = true;
                }

                _eventPublisher.PublishNotification(new StepCompleted
                {
                    EventTimeUtc         = _datetimeProvider.UtcNow,
                    Reference            = workflow.Reference,
                    ExecutionPointerId   = pointer.Id,
                    StepId               = step.Id,
                    WorkflowInstanceId   = workflow.Id,
                    WorkflowDefinitionId = workflow.WorkflowDefinitionId,
                    Version              = workflow.Version
                });
            }
            else
            {
                foreach (var branch in result.BranchValues)
                {
                    foreach (var childDefId in step.Children)
                    {
                        workflow.ExecutionPointers.Add(_pointerFactory.BuildChildPointer(def, pointer, childDefId, branch));
                    }
                }
            }
        }
Ejemplo n.º 15
0
        public override ExecutionPipelineDirective InitForExecution(IWorkflowHost host, IPersistenceProvider persistenceStore, WorkflowDefinition defintion, WorkflowInstance workflow, ExecutionPointer executionPointer)
        {
            if (!executionPointer.EventPublished)
            {
                //resolve principal to be assigned
                var resolvedUser = Principal.Compile().DynamicInvoke(workflow.Data);

                executionPointer.ExtensionAttributes["AssignedPrincipal"] = resolvedUser;
                executionPointer.ExtensionAttributes["Prompt"]            = UserPrompt;

                Dictionary <string, object> userOptions = new Dictionary <string, object>();
                foreach (var outcome in Outcomes)
                {
                    userOptions[outcome.Label ?? Convert.ToString(outcome.Value ?? "Proceed")] = outcome.Value;
                }
                executionPointer.ExtensionAttributes["UserOptions"] = userOptions;

                executionPointer.EventKey  = workflow.Id + "." + executionPointer.Id;
                executionPointer.EventName = "UserAction";
                executionPointer.Active    = false;
                persistenceStore.PersistWorkflow(workflow).Wait();
                host.SubscribeEvent(workflow.Id, executionPointer.StepId, executionPointer.EventName, executionPointer.EventKey);

                return(ExecutionPipelineDirective.Defer);
            }
            return(ExecutionPipelineDirective.Next);
        }
        public override ExecutionPipelineDirective InitForExecution(WorkflowExecutorResult executorResult, WorkflowDefinition defintion, WorkflowInstance workflow, ExecutionPointer executionPointer)
        {
            if (!executionPointer.EventPublished)
            {
                //resolve principal to be assigned
                var resolvedUser = Principal.Compile().DynamicInvoke(workflow.Data);

                executionPointer.ExtensionAttributes["AssignedPrincipal"] = resolvedUser;
                executionPointer.ExtensionAttributes["Prompt"]            = UserPrompt;

                Dictionary <string, object> userOptions = new Dictionary <string, object>();
                foreach (var outcome in Outcomes)
                {
                    userOptions[outcome.Label ?? Convert.ToString(outcome.GetValue(workflow.Data) ?? "Proceed")] = outcome.GetValue(workflow.Data);
                }
                executionPointer.ExtensionAttributes["UserOptions"] = userOptions;

                executionPointer.EventKey  = workflow.Id + "." + executionPointer.Id;
                executionPointer.EventName = "UserAction";
                executionPointer.Active    = false;

                executorResult.Subscriptions.Add(new EventSubscription()
                {
                    WorkflowId    = workflow.Id,
                    StepId        = executionPointer.StepId,
                    EventName     = executionPointer.EventName,
                    EventKey      = executionPointer.EventKey,
                    SubscribeAsOf = DateTime.Now.ToUniversalTime()
                });

                return(ExecutionPipelineDirective.Defer);
            }
            return(ExecutionPipelineDirective.Next);
        }
Ejemplo n.º 17
0
 public override ExecutionPipelineDirective BeforeExecute(IWorkflowHost host, IPersistenceProvider persistenceStore, IStepExecutionContext context, ExecutionPointer executionPointer, IStepBody body)
 {
     if (executionPointer.EventPublished)
     {
         if ((body is UserStepBody) && (executionPointer.EventData is UserAction))
         {
             (body as UserStepBody).UserAction = (executionPointer.EventData as UserAction);
             executionPointer.ExtensionAttributes["ActionUser"] = (executionPointer.EventData as UserAction).User;
         }
     }
     return(ExecutionPipelineDirective.Next);
 }
        private void Compensate(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer exceptionPointer)
        {
            var scope = new Stack <string>(exceptionPointer.Scope);

            scope.Push(exceptionPointer.Id);

            exceptionPointer.Active  = false;
            exceptionPointer.EndTime = _datetimeProvider.Now.ToUniversalTime();
            exceptionPointer.Status  = PointerStatus.Failed;

            while (scope.Any())
            {
                var pointerId = scope.Pop();
                var pointer   = workflow.ExecutionPointers.First(x => x.Id == pointerId);
                var step      = def.Steps.First(x => x.Id == pointer.StepId);

                var resume = true;
                var revert = false;

                if (scope.Any())
                {
                    var parentId      = scope.Peek();
                    var parentPointer = workflow.ExecutionPointers.First(x => x.Id == parentId);
                    var parentStep    = def.Steps.First(x => x.Id == parentPointer.StepId);
                    resume = parentStep.ResumeChildrenAfterCompensation;
                    revert = parentStep.RevertChildrenAfterCompensation;
                }

                if ((step.ErrorBehavior ?? WorkflowErrorHandling.Compensate) != WorkflowErrorHandling.Compensate)
                {
                    SelectErrorStrategy(step.ErrorBehavior ?? WorkflowErrorHandling.Retry, workflow, def, pointer, step);
                    continue;
                }

                if (step.CompensationStepId.HasValue)
                {
                    pointer.Active  = false;
                    pointer.EndTime = _datetimeProvider.Now.ToUniversalTime();
                    pointer.Status  = PointerStatus.Compensated;

                    var compensationPointer = _pointerFactory.BuildCompensationPointer(def, pointer, exceptionPointer, step.CompensationStepId.Value);
                    workflow.ExecutionPointers.Add(compensationPointer);

                    if (resume)
                    {
                        foreach (var outcomeTarget in step.Outcomes.Where(x => x.GetValue(workflow.Data) == null))
                        {
                            workflow.ExecutionPointers.Add(_pointerFactory.BuildNextPointer(def, pointer, outcomeTarget));
                        }
                    }
                }

                if (revert)
                {
                    var prevSiblings = workflow.ExecutionPointers
                                       .Where(x => pointer.Scope.SequenceEqual(x.Scope) && x.Id != pointer.Id && x.Status == PointerStatus.Complete)
                                       .OrderByDescending(x => x.EndTime)
                                       .ToList();

                    foreach (var siblingPointer in prevSiblings)
                    {
                        var siblingStep = def.Steps.First(x => x.Id == siblingPointer.StepId);
                        if (siblingStep.CompensationStepId.HasValue)
                        {
                            var compensationPointer = _pointerFactory.BuildCompensationPointer(def, siblingPointer, exceptionPointer, siblingStep.CompensationStepId.Value);
                            workflow.ExecutionPointers.Add(compensationPointer);
                            siblingPointer.Status = PointerStatus.Compensated;
                        }
                    }
                }
            }
        }
Ejemplo n.º 19
0
        private void ProcessExecutionResult(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step, ExecutionResult result, WorkflowExecutorResult workflowResult)
        {
            //TODO: refactor this into it's own class
            pointer.PersistenceData = result.PersistenceData;
            pointer.Outcome         = result.OutcomeValue;
            if (result.SleepFor.HasValue)
            {
                pointer.SleepUntil = DateTime.Now.ToUniversalTime().Add(result.SleepFor.Value);
            }

            if (!string.IsNullOrEmpty(result.EventName))
            {
                pointer.EventName = result.EventName;
                pointer.EventKey  = result.EventKey;
                pointer.Active    = false;

                workflowResult.Subscriptions.Add(new EventSubscription()
                {
                    WorkflowId    = workflow.Id,
                    StepId        = pointer.StepId,
                    EventName     = pointer.EventName,
                    EventKey      = pointer.EventKey,
                    SubscribeAsOf = result.EventAsOf
                });
            }

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

                foreach (var outcomeTarget in step.Outcomes.Where(x => object.Equals(x.GetValue(workflow.Data), result.OutcomeValue) || x.GetValue(workflow.Data) == null))
                {
                    workflow.ExecutionPointers.Add(new ExecutionPointer()
                    {
                        Id            = Guid.NewGuid().ToString(),
                        PredecessorId = pointer.Id,
                        StepId        = outcomeTarget.NextStep,
                        Active        = true,
                        ContextItem   = pointer.ContextItem,
                        StepName      = def.Steps.First(x => x.Id == outcomeTarget.NextStep).Name
                    });
                }
            }
            else
            {
                foreach (var branch in result.BranchValues)
                {
                    foreach (var childDefId in step.Children)
                    {
                        var childPointerId = Guid.NewGuid().ToString();
                        workflow.ExecutionPointers.Add(new ExecutionPointer()
                        {
                            Id            = childPointerId,
                            PredecessorId = pointer.Id,
                            StepId        = childDefId,
                            Active        = true,
                            ContextItem   = branch,
                            StepName      = def.Steps.First(x => x.Id == childDefId).Name
                        });
                        pointer.Children.Add(childPointerId);
                    }
                }
            }
        }
        public void ProcessExecutionResult(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step, ExecutionResult result, WorkflowExecutorResult workflowResult)
        {
            pointer.PersistenceData = result.PersistenceData;
            pointer.Outcome         = result.OutcomeValue;
            if (result.SleepFor.HasValue)
            {
                pointer.SleepUntil = _datetimeProvider.Now.ToUniversalTime().Add(result.SleepFor.Value);
                pointer.Status     = PointerStatus.Sleeping;
            }

            if (!string.IsNullOrEmpty(result.EventName))
            {
                pointer.EventName = result.EventName;
                pointer.EventKey  = result.EventKey;
                pointer.Active    = false;
                pointer.Status    = PointerStatus.WaitingForEvent;

                workflowResult.Subscriptions.Add(new EventSubscription()
                {
                    WorkflowId    = workflow.Id,
                    StepId        = pointer.StepId,
                    EventName     = pointer.EventName,
                    EventKey      = pointer.EventKey,
                    SubscribeAsOf = result.EventAsOf
                });
            }

            if (result.Proceed)
            {
                pointer.Active  = false;
                pointer.EndTime = _datetimeProvider.Now.ToUniversalTime();
                pointer.Status  = PointerStatus.Complete;

                foreach (var outcomeTarget in step.Outcomes.Where(x => object.Equals(x.GetValue(workflow.Data), result.OutcomeValue) || x.GetValue(workflow.Data) == null))
                {
                    workflow.ExecutionPointers.Add(_pointerFactory.BuildNextPointer(def, pointer, outcomeTarget));
                }
            }
            else
            {
                foreach (var branch in result.BranchValues)
                {
                    foreach (var childDefId in step.Children)
                    {
                        workflow.ExecutionPointers.Add(_pointerFactory.BuildChildPointer(def, pointer, childDefId, branch));
                    }
                }
            }
        }
Ejemplo n.º 21
0
        internal static WorkflowInstance ToWorkflowInstance(this PersistedWorkflow instance)
        {
            WorkflowInstance result = new WorkflowInstance();

            result.Data                 = JsonConvert.DeserializeObject(instance.Data, SerializerSettings);
            result.Description          = instance.Description;
            result.Reference            = instance.Reference;
            result.Id                   = instance.InstanceId.ToString();
            result.NextExecution        = instance.NextExecution;
            result.Version              = instance.Version;
            result.WorkflowDefinitionId = instance.WorkflowDefinitionId;
            result.Status               = instance.Status;
            result.CreateTime           = DateTime.SpecifyKind(instance.CreateTime, DateTimeKind.Utc);
            if (instance.CompleteTime.HasValue)
            {
                result.CompleteTime = DateTime.SpecifyKind(instance.CompleteTime.Value, DateTimeKind.Utc);
            }

            result.ExecutionPointers = new ExecutionPointerCollection(instance.ExecutionPointers.Count + 8);

            foreach (var ep in instance.ExecutionPointers)
            {
                var pointer = new ExecutionPointer();

                pointer.Id     = ep.Id;
                pointer.StepId = ep.StepId;
                pointer.Active = ep.Active;

                if (ep.SleepUntil.HasValue)
                {
                    pointer.SleepUntil = DateTime.SpecifyKind(ep.SleepUntil.Value, DateTimeKind.Utc);
                }

                pointer.PersistenceData = JsonConvert.DeserializeObject(ep.PersistenceData ?? string.Empty, SerializerSettings);

                if (ep.StartTime.HasValue)
                {
                    pointer.StartTime = DateTime.SpecifyKind(ep.StartTime.Value, DateTimeKind.Utc);
                }

                if (ep.EndTime.HasValue)
                {
                    pointer.EndTime = DateTime.SpecifyKind(ep.EndTime.Value, DateTimeKind.Utc);
                }

                pointer.StepName = ep.StepName;

                pointer.RetryCount    = ep.RetryCount;
                pointer.PredecessorId = ep.PredecessorId;
                pointer.ContextItem   = JsonConvert.DeserializeObject(ep.ContextItem ?? string.Empty, SerializerSettings);

                if (!string.IsNullOrEmpty(ep.Children))
                {
                    pointer.Children = ep.Children.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                }

                pointer.EventName      = ep.EventName;
                pointer.EventKey       = ep.EventKey;
                pointer.EventPublished = ep.EventPublished;
                pointer.EventData      = JsonConvert.DeserializeObject(ep.EventData ?? string.Empty, SerializerSettings);
                pointer.Outcome        = JsonConvert.DeserializeObject(ep.Outcome ?? string.Empty, SerializerSettings);
                pointer.Status         = ep.Status;

                if (!string.IsNullOrEmpty(ep.Scope))
                {
                    pointer.Scope = new List <string>(ep.Scope.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
                }

                foreach (var attr in ep.ExtensionAttributes)
                {
                    pointer.ExtensionAttributes[attr.AttributeKey] = JsonConvert.DeserializeObject(attr.AttributeValue, SerializerSettings);
                }

                result.ExecutionPointers.Add(pointer);
            }

            return(result);
        }
        private void SelectErrorStrategy(WorkflowErrorHandling errorOption, WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step)
        {
            switch (errorOption)
            {
            case WorkflowErrorHandling.Retry:
                pointer.RetryCount++;
                pointer.SleepUntil = _datetimeProvider.Now.ToUniversalTime().Add(step.RetryInterval ?? def.DefaultErrorRetryInterval ?? _options.ErrorRetryInterval);
                step.PrimeForRetry(pointer);
                break;

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

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

            case WorkflowErrorHandling.Compensate:
                Compensate(workflow, def, pointer);
                break;
            }
        }
Ejemplo n.º 23
0
        public void Handle(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer exceptionPointer, WorkflowStep exceptionStep, Exception exception, Queue <ExecutionPointer> bubbleUpQueue)
        {
            var scope = new Stack <string>(exceptionPointer.Scope.Reverse());

            scope.Push(exceptionPointer.Id);

            while (scope.Any())
            {
                var pointerId    = scope.Pop();
                var scopePointer = workflow.ExecutionPointers.FindById(pointerId);
                var scopeStep    = def.Steps.FindById(scopePointer.StepId);

                var resume = true;
                var revert = false;

                var txnStack = new Stack <string>(scope.Reverse());
                while (txnStack.Count > 0)
                {
                    var parentId      = txnStack.Pop();
                    var parentPointer = workflow.ExecutionPointers.FindById(parentId);
                    var parentStep    = def.Steps.FindById(parentPointer.StepId);
                    if ((!parentStep.ResumeChildrenAfterCompensation) || (parentStep.RevertChildrenAfterCompensation))
                    {
                        resume = parentStep.ResumeChildrenAfterCompensation;
                        revert = parentStep.RevertChildrenAfterCompensation;
                        break;
                    }
                }

                if ((scopeStep.ErrorBehavior ?? WorkflowErrorHandling.Compensate) != WorkflowErrorHandling.Compensate)
                {
                    bubbleUpQueue.Enqueue(scopePointer);
                    continue;
                }

                scopePointer.Active  = false;
                scopePointer.EndTime = _datetimeProvider.UtcNow;
                scopePointer.Status  = PointerStatus.Failed;

                if (scopeStep.CompensationStepId.HasValue)
                {
                    scopePointer.Status = PointerStatus.Compensated;

                    var compensationPointer = _pointerFactory.BuildCompensationPointer(def, scopePointer, exceptionPointer, scopeStep.CompensationStepId.Value);
                    workflow.ExecutionPointers.Add(compensationPointer);

                    if (resume)
                    {
                        foreach (var outcomeTarget in scopeStep.Outcomes.Where(x => x.Matches(workflow.Data)))
                        {
                            workflow.ExecutionPointers.Add(_pointerFactory.BuildNextPointer(def, scopePointer, outcomeTarget));
                        }
                    }
                }

                if (revert)
                {
                    var prevSiblings = workflow.ExecutionPointers
                                       .Where(x => scopePointer.Scope.SequenceEqual(x.Scope) && x.Id != scopePointer.Id && x.Status == PointerStatus.Complete)
                                       .OrderByDescending(x => x.EndTime)
                                       .ToList();

                    foreach (var siblingPointer in prevSiblings)
                    {
                        var siblingStep = def.Steps.FindById(siblingPointer.StepId);
                        if (siblingStep.CompensationStepId.HasValue)
                        {
                            var compensationPointer = _pointerFactory.BuildCompensationPointer(def, siblingPointer, exceptionPointer, siblingStep.CompensationStepId.Value);
                            workflow.ExecutionPointers.Add(compensationPointer);
                            siblingPointer.Status = PointerStatus.Compensated;
                        }
                    }
                }
            }
        }
Ejemplo n.º 24
0
        private async Task ExecuteStep(WorkflowInstance workflow, WorkflowStep step, ExecutionPointer pointer, WorkflowExecutorResult wfResult, WorkflowDefinition def, CancellationToken cancellationToken = default)
        {
            IStepExecutionContext context = new StepExecutionContext
            {
                Workflow          = workflow,
                Step              = step,
                PersistenceData   = pointer.PersistenceData,
                ExecutionPointer  = pointer,
                Item              = pointer.ContextItem,
                CancellationToken = cancellationToken
            };

            using (var scope = _scopeProvider.CreateScope(context))
            {
                _logger.LogDebug("Starting step {0} on workflow {1}", step.Name, workflow.Id);

                IStepBody body         = step.ConstructBody(scope.ServiceProvider);
                var       stepExecutor = scope.ServiceProvider.GetRequiredService <IStepExecutor>();

                if (body == null)
                {
                    _logger.LogError("Unable to construct step body {0}", step.BodyType.ToString());
                    pointer.SleepUntil = _datetimeProvider.UtcNow.Add(_options.ErrorRetryInterval);
                    wfResult.Errors.Add(new ExecutionError
                    {
                        WorkflowId         = workflow.Id,
                        ExecutionPointerId = pointer.Id,
                        ErrorTime          = _datetimeProvider.UtcNow,
                        Message            = $"Unable to construct step body {step.BodyType}"
                    });
                    return;
                }

                foreach (var input in step.Inputs)
                {
                    input.AssignInput(workflow.Data, body, context);
                }

                switch (step.BeforeExecute(wfResult, context, pointer, body))
                {
                case ExecutionPipelineDirective.Defer:
                    return;

                case ExecutionPipelineDirective.EndWorkflow:
                    workflow.Status       = WorkflowStatus.Complete;
                    workflow.CompleteTime = _datetimeProvider.UtcNow;
                    return;
                }

                var result = await stepExecutor.ExecuteStep(context, body);

                if (result.Proceed)
                {
                    foreach (var output in step.Outputs)
                    {
                        output.AssignOutput(workflow.Data, body, context);
                    }
                }

                _executionResultProcessor.ProcessExecutionResult(workflow, def, pointer, step, result, wfResult);
                step.AfterExecute(wfResult, context, result, pointer);
            }
        }
Ejemplo n.º 25
0
        public override void AfterWorkflowIteration(WorkflowExecutorResult executorResult, WorkflowDefinition defintion, WorkflowInstance workflow, ExecutionPointer executionPointer)
        {
            base.AfterWorkflowIteration(executorResult, defintion, workflow, executionPointer);
            var func = _cancelCondition.Compile();

            if (func((TData)workflow.Data))
            {
                executionPointer.EndTime = DateTime.Now.ToUniversalTime();
                executionPointer.Active  = false;
            }
        }