예제 #1
0
        async Task <OrchestrationExecutionCursor> ExecuteOrchestrationAsync(OrchestrationRuntimeState runtimeState)
        {
            TaskOrchestration taskOrchestration = this.objectManager.GetObject(runtimeState.Name, runtimeState.Version);

            if (taskOrchestration == null)
            {
                throw TraceHelper.TraceExceptionInstance(
                          TraceEventType.Error,
                          "TaskOrchestrationDispatcher-TypeMissing",
                          runtimeState.OrchestrationInstance,
                          new TypeMissingException($"Orchestration not found: ({runtimeState.Name}, {runtimeState.Version})"));
            }

            var dispatchContext = new DispatchMiddlewareContext();

            dispatchContext.SetProperty(runtimeState.OrchestrationInstance);
            dispatchContext.SetProperty(taskOrchestration);
            dispatchContext.SetProperty(runtimeState);

            var executor = new TaskOrchestrationExecutor(runtimeState, taskOrchestration, orchestrationService.EventBehaviourForContinueAsNew);

            IEnumerable <OrchestratorAction> decisions = Enumerable.Empty <OrchestratorAction>();

            await this.dispatchPipeline.RunAsync(dispatchContext, _ =>
            {
                decisions = executor.Execute();
                return(CompletedTask);
            });

            return(new OrchestrationExecutionCursor(runtimeState, taskOrchestration, executor, decisions));
        }
예제 #2
0
        async Task <IEnumerable <OrchestratorAction> > ExecuteOrchestrationAsync(OrchestrationRuntimeState runtimeState)
        {
            TaskOrchestration taskOrchestration = objectManager.GetObject(runtimeState.Name, runtimeState.Version);

            if (taskOrchestration == null)
            {
                throw TraceHelper.TraceExceptionInstance(
                          TraceEventType.Error,
                          "TaskOrchestrationDispatcher-TypeMissing",
                          runtimeState.OrchestrationInstance,
                          new TypeMissingException($"Orchestration not found: ({runtimeState.Name}, {runtimeState.Version})"));
            }

            var dispatchContext = new DispatchMiddlewareContext();

            dispatchContext.SetProperty(runtimeState.OrchestrationInstance);
            dispatchContext.SetProperty(taskOrchestration);
            dispatchContext.SetProperty(runtimeState);

            IEnumerable <OrchestratorAction> decisions = null;

            await this.dispatchPipeline.RunAsync(dispatchContext, _ =>
            {
                var taskOrchestrationExecutor = new TaskOrchestrationExecutor(runtimeState, taskOrchestration);
                decisions = taskOrchestrationExecutor.Execute();

                return(Task.FromResult(0));
            });

            return(decisions);
        }
예제 #3
0
 public TaskOrchestrationExecutor(OrchestrationRuntimeState orchestrationRuntimeState,
                                  TaskOrchestration taskOrchestration)
 {
     decisionScheduler = new SynchronousTaskScheduler();
     context           = new TaskOrchestrationContext(orchestrationRuntimeState.OrchestrationInstance, decisionScheduler);
     this.orchestrationRuntimeState = orchestrationRuntimeState;
     this.taskOrchestration         = taskOrchestration;
 }
 public TaskOrchestrationExecutor(OrchestrationRuntimeState orchestrationRuntimeState,
                                  TaskOrchestration taskOrchestration, BehaviorOnContinueAsNew eventBehaviourForContinueAsNew)
 {
     this.decisionScheduler         = new SynchronousTaskScheduler();
     this.context                   = new TaskOrchestrationContext(orchestrationRuntimeState.OrchestrationInstance, this.decisionScheduler);
     this.orchestrationRuntimeState = orchestrationRuntimeState;
     this.taskOrchestration         = taskOrchestration;
     this.skipCarryOverEvents       = eventBehaviourForContinueAsNew == BehaviorOnContinueAsNew.Ignore;
 }
예제 #5
0
 public OrchestrationExecutionCursor(
     OrchestrationRuntimeState state,
     TaskOrchestration orchestration,
     TaskOrchestrationExecutor executor,
     IEnumerable <OrchestratorAction> latestDecisions)
 {
     this.RuntimeState          = state;
     this.TaskOrchestration     = orchestration;
     this.OrchestrationExecutor = executor;
     this.LatestDecisions       = latestDecisions;
 }
 public TaskOrchestrationExecutor(
     OrchestrationRuntimeState orchestrationRuntimeState,
     TaskOrchestration taskOrchestration,
     BehaviorOnContinueAsNew eventBehaviourForContinueAsNew,
     ErrorPropagationMode errorPropagationMode = ErrorPropagationMode.SerializeExceptions)
 {
     this.decisionScheduler = new SynchronousTaskScheduler();
     this.context           = new TaskOrchestrationContext(
         orchestrationRuntimeState.OrchestrationInstance,
         this.decisionScheduler,
         errorPropagationMode);
     this.orchestrationRuntimeState = orchestrationRuntimeState;
     this.taskOrchestration         = taskOrchestration;
     this.skipCarryOverEvents       = eventBehaviourForContinueAsNew == BehaviorOnContinueAsNew.Ignore;
 }
예제 #7
0
        /// <summary>
        /// Method to process a new work item
        /// </summary>
        /// <param name="workItem">The work item to process</param>
        protected async Task <bool> OnProcessWorkItemAsync(TaskOrchestrationWorkItem workItem)
        {
            var messagesToSend       = new List <TaskMessage>();
            var timerMessages        = new List <TaskMessage>();
            var orchestratorMessages = new List <TaskMessage>();
            var isCompleted          = false;
            var continuedAsNew       = false;
            var isInterrupted        = false;

            // correlation
            CorrelationTraceClient.Propagate(() => CorrelationTraceContext.Current = workItem.TraceContext);

            ExecutionStartedEvent continueAsNewExecutionStarted = null;
            TaskMessage           continuedAsNewMessage         = null;
            IList <HistoryEvent>  carryOverEvents = null;
            string carryOverStatus = null;

            OrchestrationRuntimeState runtimeState = workItem.OrchestrationRuntimeState;

            runtimeState.AddEvent(new OrchestratorStartedEvent(-1));

            OrchestrationRuntimeState originalOrchestrationRuntimeState = runtimeState;

            OrchestrationState instanceState = null;

            if (!ReconcileMessagesWithState(workItem))
            {
                // TODO : mark an orchestration as faulted if there is data corruption
                TraceHelper.TraceSession(
                    TraceEventType.Error,
                    "TaskOrchestrationDispatcher-DeletedOrchestration",
                    runtimeState.OrchestrationInstance?.InstanceId,
                    "Received result for a deleted orchestration");
                isCompleted = true;
            }
            else
            {
                do
                {
                    continuedAsNew        = false;
                    continuedAsNewMessage = null;

                    TraceHelper.TraceInstance(
                        TraceEventType.Verbose,
                        "TaskOrchestrationDispatcher-ExecuteUserOrchestration-Begin",
                        runtimeState.OrchestrationInstance,
                        "Executing user orchestration: {0}",
                        DataConverter.Serialize(runtimeState.GetOrchestrationRuntimeStateDump(), true));

                    if (workItem.Cursor == null)
                    {
                        workItem.Cursor = await ExecuteOrchestrationAsync(runtimeState);
                    }
                    else
                    {
                        await ResumeOrchestrationAsync(workItem.Cursor);
                    }

                    IReadOnlyList <OrchestratorAction> decisions = workItem.Cursor.LatestDecisions.ToList();

                    TraceHelper.TraceInstance(
                        TraceEventType.Information,
                        "TaskOrchestrationDispatcher-ExecuteUserOrchestration-End",
                        runtimeState.OrchestrationInstance,
                        "Executed user orchestration. Received {0} orchestrator actions: {1}",
                        decisions.Count,
                        string.Join(", ", decisions.Select(d => d.Id + ":" + d.OrchestratorActionType)));

                    foreach (OrchestratorAction decision in decisions)
                    {
                        TraceHelper.TraceInstance(
                            TraceEventType.Information,
                            "TaskOrchestrationDispatcher-ProcessOrchestratorAction",
                            runtimeState.OrchestrationInstance,
                            "Processing orchestrator action of type {0}",
                            decision.OrchestratorActionType);
                        switch (decision.OrchestratorActionType)
                        {
                        case OrchestratorActionType.ScheduleOrchestrator:
                            messagesToSend.Add(
                                ProcessScheduleTaskDecision((ScheduleTaskOrchestratorAction)decision, runtimeState,
                                                            IncludeParameters));
                            break;

                        case OrchestratorActionType.CreateTimer:
                            var timerOrchestratorAction = (CreateTimerOrchestratorAction)decision;
                            timerMessages.Add(ProcessCreateTimerDecision(timerOrchestratorAction, runtimeState));
                            break;

                        case OrchestratorActionType.CreateSubOrchestration:
                            var createSubOrchestrationAction = (CreateSubOrchestrationAction)decision;
                            orchestratorMessages.Add(
                                ProcessCreateSubOrchestrationInstanceDecision(createSubOrchestrationAction,
                                                                              runtimeState, IncludeParameters));
                            break;

                        case OrchestratorActionType.SendEvent:
                            var sendEventAction = (SendEventOrchestratorAction)decision;
                            orchestratorMessages.Add(
                                ProcessSendEventDecision(sendEventAction, runtimeState));
                            break;

                        case OrchestratorActionType.OrchestrationComplete:
                            OrchestrationCompleteOrchestratorAction completeDecision = (OrchestrationCompleteOrchestratorAction)decision;
                            TaskMessage workflowInstanceCompletedMessage             =
                                ProcessWorkflowCompletedTaskDecision(completeDecision, runtimeState, IncludeDetails, out continuedAsNew);
                            if (workflowInstanceCompletedMessage != null)
                            {
                                // Send complete message to parent workflow or to itself to start a new execution
                                // Store the event so we can rebuild the state
                                carryOverEvents = null;
                                if (continuedAsNew)
                                {
                                    continuedAsNewMessage         = workflowInstanceCompletedMessage;
                                    continueAsNewExecutionStarted = workflowInstanceCompletedMessage.Event as ExecutionStartedEvent;
                                    if (completeDecision.CarryoverEvents.Any())
                                    {
                                        carryOverEvents = completeDecision.CarryoverEvents.ToList();
                                        completeDecision.CarryoverEvents.Clear();
                                    }
                                }
                                else
                                {
                                    orchestratorMessages.Add(workflowInstanceCompletedMessage);
                                }
                            }

                            isCompleted = !continuedAsNew;
                            break;

                        default:
                            throw TraceHelper.TraceExceptionInstance(
                                      TraceEventType.Error,
                                      "TaskOrchestrationDispatcher-UnsupportedDecisionType",
                                      runtimeState.OrchestrationInstance,
                                      new NotSupportedException("decision type not supported"));
                        }

                        // Underlying orchestration service provider may have a limit of messages per call, to avoid the situation
                        // we keep on asking the provider if message count is ok and stop processing new decisions if not.
                        //
                        // We also put in a fake timer to force next orchestration task for remaining messages
                        int totalMessages = messagesToSend.Count + orchestratorMessages.Count + timerMessages.Count;
                        if (this.orchestrationService.IsMaxMessageCountExceeded(totalMessages, runtimeState))
                        {
                            TraceHelper.TraceInstance(
                                TraceEventType.Information,
                                "TaskOrchestrationDispatcher-MaxMessageCountReached",
                                runtimeState.OrchestrationInstance,
                                "MaxMessageCount reached.  Adding timer to process remaining events in next attempt.");

                            if (isCompleted || continuedAsNew)
                            {
                                TraceHelper.TraceInstance(
                                    TraceEventType.Information,
                                    "TaskOrchestrationDispatcher-OrchestrationAlreadyCompleted",
                                    runtimeState.OrchestrationInstance,
                                    "Orchestration already completed.  Skip adding timer for splitting messages.");
                                break;
                            }

                            var dummyTimer = new CreateTimerOrchestratorAction
                            {
                                Id     = FrameworkConstants.FakeTimerIdToSplitDecision,
                                FireAt = DateTime.UtcNow
                            };

                            timerMessages.Add(ProcessCreateTimerDecision(dummyTimer, runtimeState));
                            isInterrupted = true;
                            break;
                        }
                    }

                    // finish up processing of the work item
                    if (!continuedAsNew && runtimeState.Events.Last().EventType != EventType.OrchestratorCompleted)
                    {
                        runtimeState.AddEvent(new OrchestratorCompletedEvent(-1));
                    }

                    if (isCompleted)
                    {
                        TraceHelper.TraceSession(TraceEventType.Information, "TaskOrchestrationDispatcher-DeletingSessionState", workItem.InstanceId, "Deleting session state");
                        if (runtimeState.ExecutionStartedEvent != null)
                        {
                            instanceState = Utils.BuildOrchestrationState(runtimeState);
                        }
                    }
                    else
                    {
                        if (continuedAsNew)
                        {
                            TraceHelper.TraceSession(
                                TraceEventType.Information,
                                "TaskOrchestrationDispatcher-UpdatingStateForContinuation",
                                workItem.InstanceId,
                                "Updating state for continuation");

                            runtimeState = new OrchestrationRuntimeState();
                            runtimeState.AddEvent(new OrchestratorStartedEvent(-1));
                            runtimeState.AddEvent(continueAsNewExecutionStarted);
                            runtimeState.Status = workItem.OrchestrationRuntimeState.Status ?? carryOverStatus;
                            carryOverStatus     = workItem.OrchestrationRuntimeState.Status;

                            if (carryOverEvents != null)
                            {
                                foreach (var historyEvent in carryOverEvents)
                                {
                                    runtimeState.AddEvent(historyEvent);
                                }
                            }

                            runtimeState.AddEvent(new OrchestratorCompletedEvent(-1));
                            workItem.OrchestrationRuntimeState = runtimeState;

                            TaskOrchestration newOrchestration = this.objectManager.GetObject(
                                runtimeState.Name,
                                continueAsNewExecutionStarted.Version);

                            workItem.Cursor = new OrchestrationExecutionCursor(
                                runtimeState,
                                newOrchestration,
                                new TaskOrchestrationExecutor(
                                    runtimeState,
                                    newOrchestration,
                                    orchestrationService.EventBehaviourForContinueAsNew),
                                latestDecisions: null);

                            if (workItem.LockedUntilUtc < DateTime.UtcNow.AddMinutes(1))
                            {
                                await orchestrationService.RenewTaskOrchestrationWorkItemLockAsync(workItem);
                            }
                        }

                        instanceState = Utils.BuildOrchestrationState(runtimeState);
                    }
                } while (continuedAsNew);
            }

            workItem.OrchestrationRuntimeState = originalOrchestrationRuntimeState;

            runtimeState.Status = runtimeState.Status ?? carryOverStatus;

            await this.orchestrationService.CompleteTaskOrchestrationWorkItemAsync(
                workItem,
                runtimeState,
                continuedAsNew?null : messagesToSend,
                orchestratorMessages,
                continuedAsNew?null : timerMessages,
                continuedAsNewMessage,
                instanceState);

            workItem.OrchestrationRuntimeState = runtimeState;

            return(isCompleted || continuedAsNew || isInterrupted);
        }