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 (pointer.Status == PointerStatus.ValidationFailed)
            {
                result.Proceed = false;
            }

            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));
                    }
                }
            }
        }
        public void should_advance_workflow()
        {
            //arrange
            var definition = new WorkflowDefinition();
            var pointer1   = new ExecutionPointer()
            {
                Active = true, StepId = 0, Status = PointerStatus.Running
            };
            var pointer2 = new ExecutionPointer();
            var outcome  = new StepOutcome()
            {
                NextStep = 1
            };
            var step           = A.Fake <WorkflowStep>();
            var workflowResult = new WorkflowExecutorResult();
            var instance       = GivenWorkflow(pointer1);
            var result         = ExecutionResult.Next();

            A.CallTo(() => step.Outcomes).Returns(new List <StepOutcome>()
            {
                outcome
            });
            A.CallTo(() => PointerFactory.BuildNextPointer(definition, pointer1, outcome)).Returns(pointer2);

            //act
            Subject.ProcessExecutionResult(instance, definition, pointer1, step, result, workflowResult);

            //assert
            pointer1.Active.Should().BeFalse();
            pointer1.Status.Should().Be(PointerStatus.Complete);
            pointer1.EndTime.Should().NotBeNull();

            A.CallTo(() => PointerFactory.BuildNextPointer(definition, pointer1, outcome)).MustHaveHappened();
            instance.ExecutionPointers.Should().Contain(pointer2);
        }
Ejemplo n.º 3
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.First(x => x.Id == 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.First(x => x.Id == 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.Now.ToUniversalTime();
                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.GetValue(workflow.Data) == null))
                        {
                            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.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.º 4
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));
                }
                _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));
                    }
                }
            }
        }