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); }
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; } } } } }
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)); } } } }