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;
                        }
                    }
                }
            }
        }
示例#2
0
        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).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;
                        }
                    }
                }
            }
        }