Exemplo n.º 1
0
        public string ReplayOrchestration(string name, string version, string serializedHistoryEvents)
        {

            TaskOrchestration taskOrchestration = this.orchestrationObjectManager.GetObject(name, version);

            IList<HistoryEvent> replayEvents = this.DeserializeHistoryEvents(serializedHistoryEvents);

            if (replayEvents.Any(re => re.EventType == EventType.GenericEvent))
            {
                throw new InvalidOperationException("Cannot replay with GenericEvent");
            }

            var runtimeState = new OrchestrationRuntimeState(this.DeserializeHistoryEvents(serializedHistoryEvents));

            TaskOrchestrationExecutor executor = new TaskOrchestrationExecutor(runtimeState, taskOrchestration);
            return JsonConvert.SerializeObject(executor.Execute(), new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.All,
                Formatting = Formatting.Indented
            });
        }
        public async Task CompleteTaskOrchestrationWorkItemAsync(
            TaskOrchestrationWorkItem workItem,
            OrchestrationRuntimeState newOrchestrationRuntimeState,
            IList <TaskMessage> outboundMessages,
            IList <TaskMessage> orchestratorMessages,
            IList <TaskMessage> timerMessages,
            TaskMessage continuedAsNewMessage,
            OrchestrationState orchestrationState)
        {
            SessionInformation sessionInfo = GetSessionInfo(workItem.InstanceId);

            if (continuedAsNewMessage != null)
            {
                throw new Exception("ContinueAsNew is not supported yet");
            }

            bool isComplete = workItem.OrchestrationRuntimeState.OrchestrationStatus.IsTerminalState();

            IList <OrchestrationInstance>             sessionsToEnqueue = null;
            List <Message <Guid, TaskMessageItem> >   scheduledMessages = null;
            List <Message <string, TaskMessageItem> > activityMessages  = null;

            await RetryHelper.ExecuteWithRetryOnTransient(async() =>
            {
                bool retryOnException;
                do
                {
                    try
                    {
                        retryOnException  = false;
                        sessionsToEnqueue = null;
                        scheduledMessages = null;
                        activityMessages  = null;

                        using (var txn = this.stateManager.CreateTransaction())
                        {
                            if (outboundMessages?.Count > 0)
                            {
                                activityMessages = outboundMessages.Select(m => new Message <string, TaskMessageItem>(Guid.NewGuid().ToString(), new TaskMessageItem(m))).ToList();
                                await this.activitiesProvider.SendBatchBeginAsync(txn, activityMessages);
                            }

                            if (timerMessages?.Count > 0)
                            {
                                scheduledMessages = timerMessages.Select(m => new Message <Guid, TaskMessageItem>(Guid.NewGuid(), new TaskMessageItem(m))).ToList();
                                await this.scheduledMessagesProvider.SendBatchBeginAsync(txn, scheduledMessages);
                            }

                            if (orchestratorMessages?.Count > 0)
                            {
                                if (workItem.OrchestrationRuntimeState?.ParentInstance != null)
                                {
                                    sessionsToEnqueue = await this.orchestrationProvider.TryAppendMessageBatchAsync(txn, orchestratorMessages.Select(tm => new TaskMessageItem(tm)));
                                }
                                else
                                {
                                    await this.orchestrationProvider.AppendMessageBatchAsync(txn, orchestratorMessages.Select(tm => new TaskMessageItem(tm)));
                                    sessionsToEnqueue = orchestratorMessages.Select(m => m.OrchestrationInstance).ToList();
                                }
                            }

                            await this.orchestrationProvider.CompleteMessages(txn, sessionInfo.Instance, sessionInfo.LockTokens);

                            // When an orchestration is completed, we need to drop the session which involves 2 steps (1) Removing the row from sessions
                            // (2) Dropping the session messages dictionary. The second step is done in background thread for performance so is not
                            // part of transaction. Since it will happen outside the trasanction, if this transaction fails for some reason and we dropped
                            // the session as part of this transaction, we wouldn't have updated the session state but would have lost the messages
                            // in the session messages dictionary which are needed for state to reach complete state (when the orchestration is picked up again in next fetch).
                            // So we don't want to drop session as part of this transaction.
                            // Instead, we drop the session as part of a subsequent different transaction.
                            // However, framework passes us 'null' value for 'newOrchestrationRuntimeState' when orchestration is completed and
                            // if we updated the session state to null and this transaction succeded, and a node failures occurs and we
                            // never call the subsequent transaction, we will lose the runtime state of orchestration and never will be able to
                            // mark it as complete even if it is. So we use the work item's runtime state when 'newOrchestrationRuntimeState' is null
                            // so that the latest state is what is stored for the session.
                            // As part of next transaction, we are going to remove the row anyway for the session and it doesn't matter to update it to 'null'.
                            await this.orchestrationProvider.UpdateSessionState(txn, sessionInfo.Instance, newOrchestrationRuntimeState ?? workItem.OrchestrationRuntimeState);

                            // We skip writing to instanceStore when orchestration reached terminal state to avoid a minor timing issue that
                            // wait for an orchestration completes but another orchestration with the same name cannot be started immediately
                            // because the session is still in store. We update the instance store on orchestration completion and drop the
                            // session as part of the next atomic transaction.
                            if (this.instanceStore != null && orchestrationState != null && !isComplete)
                            {
                                await this.instanceStore.WriteEntitiesAsync(txn, new InstanceEntityBase[]
                                {
                                    new OrchestrationStateInstanceEntity()
                                    {
                                        State = orchestrationState
                                    }
                                });
                            }
                            await txn.CommitAsync();
                        }
                    }
                    catch (FabricReplicationOperationTooLargeException ex)
                    {
                        ServiceFabricProviderEventSource.Tracing.ExceptionInReliableCollectionOperations($"OrchestrationInstance = {sessionInfo.Instance}, Action = {nameof(CompleteTaskOrchestrationWorkItemAsync)}", ex.ToString());
                        retryOnException             = true;
                        newOrchestrationRuntimeState = null;
                        outboundMessages             = null;
                        timerMessages        = null;
                        orchestratorMessages = null;
                        if (orchestrationState != null)
                        {
                            orchestrationState.OrchestrationStatus = OrchestrationStatus.Failed;
                            orchestrationState.Output = $"Fabric exception when trying to process orchestration: {ex}. Investigate and consider reducing the serialization size of orchestration inputs/outputs/overall length to avoid the issue.";
                        }
                    }
                } while (retryOnException);
            }, uniqueActionIdentifier : $"OrchestrationId = '{workItem.InstanceId}', Action = '{nameof(CompleteTaskOrchestrationWorkItemAsync)}'");

            if (activityMessages != null)
            {
                this.activitiesProvider.SendBatchComplete(activityMessages);
            }
            if (scheduledMessages != null)
            {
                this.scheduledMessagesProvider.SendBatchComplete(scheduledMessages);
            }
            if (sessionsToEnqueue != null)
            {
                foreach (var instance in sessionsToEnqueue)
                {
                    this.orchestrationProvider.TryEnqueueSession(instance);
                }
            }

            if (isComplete)
            {
                await HandleCompletedOrchestration(workItem);
            }
        }
 /// <inheritdoc />
 public bool IsMaxMessageCountExceeded(int currentMessageCount, OrchestrationRuntimeState runtimeState)
 {
     return(currentMessageCount > MaxConcurrentTaskOrchestrationWorkItems);
 }
        public async Task <TaskOrchestrationWorkItem> GetSingleOrchestrationSessionAsync(TimeSpan receiveTimeout, CancellationToken cancellationToken)
        {
            Stopwatch timer = Stopwatch.StartNew();
            int       orchestrationCount = activeOrchestrationLocks.Keys.Count;

            if (orchestrationCount == 0)
            {
                return(null);
            }

            string[] orchestrationIds         = activeOrchestrationLocks.Keys.ToArray();
            int      currentIndex             = 0;
            int      count                    = 0;
            int      perOrchestrationWaitTime = 5; // No particular reason for this value.

            while (!((int)timer.ElapsedMilliseconds > receiveTimeout.Milliseconds && cancellationToken.IsCancellationRequested))
            {
                string orchestrationId = orchestrationIds[currentIndex];
                //await this.logger.LogAsync($"Attempting to grab an orchestration task item for orchestration {orchestrationId}");
                bool gotOrchestrationLock = await activeOrchestrationLocks[orchestrationId].WaitAsync(perOrchestrationWaitTime);
                if (gotOrchestrationLock)
                {
                    List <TaskMessage> queuedMessages = await this.GetOrchestrationControlQueueMessages(orchestrationId);

                    if (queuedMessages.Count > 0)
                    {
                        //await this.logger.LogAsync($"Taking lock on {orchestrationId} after {count} attempts");
                        OrchestrationRuntimeState runtimeState = await GetOrchestrationRuntimeState(orchestrationId);

                        return(new TaskOrchestrationWorkItem()
                        {
                            InstanceId = orchestrationId,
                            NewMessages = queuedMessages,
                            LockedUntilUtc = DateTime.UtcNow.AddHours(1), // technically it is locked indefinitely
                            OrchestrationRuntimeState = runtimeState
                        });
                    }
                    else
                    {
                        //await this.logger.LogAsync($"Nothing in queue for orchestration {orchestrationId}");
                    }

                    // Release lock and try another
                    activeOrchestrationLocks[orchestrationId].Release();
                }
                else
                {
                    await this.logger.LogAsync($"Failed to get lock on {orchestrationId}");
                }

                currentIndex += 1;
                count        += 1;
                if (currentIndex == orchestrationIds.Length)
                {
                    // reached the end of the keys, try again from the beginning
                    currentIndex = 0;
                }
            }

            return(null);
        }
Exemplo n.º 5
0
        /// <inheritdoc />
        public override async Task <string> UpdateStateAsync(OrchestrationRuntimeState newRuntimeState, OrchestrationRuntimeState oldRuntimeState, string instanceId, string executionId, string eTag)
        {
            //In case there is a runtime state for an older execution/iteration as well that needs to be committed, commit it.
            //This may be the case if a ContinueAsNew was executed on the orchestration
            if (newRuntimeState != oldRuntimeState)
            {
                eTag = await UpdateStateAsync(oldRuntimeState, instanceId, oldRuntimeState.OrchestrationInstance.ExecutionId, eTag);
            }

            return(await UpdateStateAsync(newRuntimeState, instanceId, executionId, eTag));
        }
        private async Task OrchestrationMiddleware(DispatchMiddlewareContext dispatchContext, Func <Task> next)
        {
            TaskOrchestrationShim       shim    = (TaskOrchestrationShim)dispatchContext.GetProperty <TaskOrchestration>();
            DurableOrchestrationContext context = shim.Context;

            OrchestrationRuntimeState orchestrationRuntimeState = dispatchContext.GetProperty <OrchestrationRuntimeState>();

            if (orchestrationRuntimeState.ParentInstance != null)
            {
                context.ParentInstanceId = orchestrationRuntimeState.ParentInstance.OrchestrationInstance.InstanceId;
            }

            context.InstanceId  = orchestrationRuntimeState.OrchestrationInstance.InstanceId;
            context.IsReplaying = orchestrationRuntimeState.ExecutionStartedEvent.IsPlayed;
            context.History     = orchestrationRuntimeState.Events;
            context.SetInput(orchestrationRuntimeState.Input);

            FunctionName orchestratorFunction = new FunctionName(context.Name);

            OrchestratorInfo info;

            if (!this.registeredOrchestrators.TryGetValue(orchestratorFunction, out info))
            {
                string message = this.GetInvalidOrchestratorFunctionMessage(orchestratorFunction.Name);
                this.TraceHelper.ExtensionWarningEvent(
                    this.Options.HubName,
                    orchestratorFunction.Name,
                    orchestrationRuntimeState.OrchestrationInstance.InstanceId,
                    message);
                throw new InvalidOperationException(message);
            }

            // 1. Start the functions invocation pipeline (billing, logging, bindings, and timeout tracking).
            FunctionResult result = await info.Executor.TryExecuteAsync(
                new TriggeredFunctionData
            {
                TriggerValue = context,

#pragma warning disable CS0618 // Approved for use by this extension
                InvokeHandler = userCodeInvoker =>
                {
                    // 2. Configure the shim with the inner invoker to execute the user code.
                    shim.SetFunctionInvocationCallback(userCodeInvoker);

                    // 3. Move to the next stage of the DTFx pipeline to trigger the orchestrator shim.
                    return(next());
                },
#pragma warning restore CS0618
            },
                CancellationToken.None);

            if (!context.IsCompleted)
            {
                this.TraceHelper.FunctionAwaited(
                    context.HubName,
                    context.Name,
                    context.InstanceId,
                    context.IsReplaying);
            }

            await context.RunDeferredTasks();
        }
 public void UpdateRuntimeState(OrchestrationRuntimeState runtimeState)
 {
     this.RuntimeState = runtimeState;
     this.Instance     = runtimeState.OrchestrationInstance;
 }
        public async Task <TaskOrchestrationWorkItem> LockNextTaskOrchestrationWorkItemAsync(
            TimeSpan receiveTimeout,
            INameVersionInfo[] orchestrations,
            CancellationToken cancellationToken)
        {
            var stoppableCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(
                cancellationToken, _stopCts.Token).Token;

            return(await BackoffPollingHelper.PollAsync(async() =>
            {
                using (var dbContext = _dbContextFactory())
                {
                    var instance = await LockNextInstance(dbContext, orchestrations);

                    if (instance == null)
                    {
                        return null;
                    }

                    var execution = await dbContext.Executions
                                    .Where(e => e.InstanceId == instance.InstanceId && e.ExecutionId == instance.LastExecutionId)
                                    .FirstOrDefaultAsync();

                    var events = await dbContext.Events
                                 .Where(e => e.InstanceId == instance.InstanceId && e.ExecutionId == instance.LastExecutionId)
                                 .OrderBy(e => e.SequenceNumber)
                                 .AsNoTracking()
                                 .ToArrayAsync();

                    var deserializedEvents = events
                                             .Select(e => _options.DataConverter.Deserialize <HistoryEvent>(e.Content))
                                             .ToArray();

                    var runtimeState = new OrchestrationRuntimeState(deserializedEvents);

                    var session = new EFCoreOrchestrationSession(
                        _options,
                        _dbContextFactory,
                        instance,
                        execution,
                        runtimeState,
                        _stopCts.Token);

                    var messages = await session.FetchNewMessagesAsync(dbContext);

                    if (messages.Count == 0)
                    {
                        instance.LockId = null;
                        instance.LockedUntil = DateTime.UtcNow;
                        await dbContext.SaveChangesAsync();
                        return null;
                    }

                    await dbContext.SaveChangesAsync();

                    return new TaskOrchestrationWorkItem
                    {
                        InstanceId = instance.InstanceId,
                        LockedUntilUtc = instance.LockedUntil,
                        OrchestrationRuntimeState = runtimeState,
                        NewMessages = messages,
                        Session = session
                    };
                }
            },
                                                        r => r != null,
                                                        receiveTimeout,
                                                        _options.PollingInterval,
                                                        stoppableCancellationToken));
        }
Exemplo n.º 9
0
 public static int GetEpisodeNumber(OrchestrationRuntimeState runtimeState)
 {
     return(GetEpisodeNumber(runtimeState.Events));
 }
Exemplo n.º 10
0
        /// <inheritdoc />
        public Task CompleteTaskOrchestrationWorkItemAsync(
            TaskOrchestrationWorkItem workItem,
            OrchestrationRuntimeState newOrchestrationRuntimeState,
            IList <TaskMessage> outboundMessages,
            IList <TaskMessage> orchestratorMessages,
            IList <TaskMessage> workItemTimerMessages,
            TaskMessage continuedAsNewMessage,
            OrchestrationState state)
        {
            lock (this.thisLock)
            {
                byte[] newSessionState;

                if (newOrchestrationRuntimeState == null ||
                    newOrchestrationRuntimeState.ExecutionStartedEvent == null ||
                    newOrchestrationRuntimeState.OrchestrationStatus != OrchestrationStatus.Running)
                {
                    newSessionState = null;
                }
                else
                {
                    newSessionState = SerializeOrchestrationRuntimeState(newOrchestrationRuntimeState);
                }

                this.orchestratorQueue.CompleteSession(
                    workItem.InstanceId,
                    newSessionState,
                    orchestratorMessages,
                    continuedAsNewMessage
                    );

                if (outboundMessages != null)
                {
                    foreach (TaskMessage m in outboundMessages)
                    {
                        // TODO : make async (AFFANDAR)
                        this.workerQueue.SendMessageAsync(m);
                    }
                }

                if (workItemTimerMessages != null)
                {
                    lock (this.timerLock)
                    {
                        foreach (TaskMessage m in workItemTimerMessages)
                        {
                            this.timerMessages.Add(m);
                        }
                    }
                }

                if (workItem.OrchestrationRuntimeState != newOrchestrationRuntimeState)
                {
                    var oldState = Utils.BuildOrchestrationState(workItem.OrchestrationRuntimeState);
                    CommitState(workItem.OrchestrationRuntimeState, oldState).GetAwaiter().GetResult();
                }

                if (state != null)
                {
                    CommitState(newOrchestrationRuntimeState, state).GetAwaiter().GetResult();
                }
            }

            return(Task.FromResult(0));
        }
        public override async Task CompleteTaskOrchestrationWorkItemAsync(
            TaskOrchestrationWorkItem workItem,
            OrchestrationRuntimeState newRuntimeState,
            IList <TaskMessage> outboundMessages,
            IList <TaskMessage> orchestratorMessages,
            IList <TaskMessage> timerMessages,
            TaskMessage continuedAsNewMessage,
            OrchestrationState orchestrationState)
        {
            ExtendedOrchestrationWorkItem currentWorkItem = (ExtendedOrchestrationWorkItem)workItem;

            this.traceHelper.CheckpointStarting(orchestrationState);
            Stopwatch sw = Stopwatch.StartNew();

            using SqlConnection connection = await this.GetAndOpenConnectionAsync();

            using SqlCommand command = this.GetSprocCommand(connection, "dt._CheckpointOrchestration");

            OrchestrationInstance instance  = newRuntimeState.OrchestrationInstance;
            IList <HistoryEvent>  newEvents = newRuntimeState.NewEvents;
            IList <HistoryEvent>  allEvents = newRuntimeState.Events;
            int nextSequenceNumber          = allEvents.Count - newEvents.Count;

            command.Parameters.Add("@InstanceID", SqlDbType.VarChar, size: 100).Value   = instance.InstanceId;
            command.Parameters.Add("@ExecutionID", SqlDbType.VarChar, size: 50).Value   = instance.ExecutionId;
            command.Parameters.Add("@RuntimeStatus", SqlDbType.VarChar, size: 30).Value = orchestrationState.OrchestrationStatus.ToString();
            command.Parameters.Add("@CustomStatusPayload", SqlDbType.VarChar).Value     = orchestrationState.Status ?? SqlString.Null;

            command.Parameters.AddMessageIdParameter("@DeletedEvents", workItem.NewMessages);
            command.Parameters.AddHistoryEventsParameter(
                "@NewHistoryEvents",
                newEvents,
                instance,
                nextSequenceNumber,
                currentWorkItem.EventPayloadMappings);
            command.Parameters.AddOrchestrationEventsParameter(
                "@NewOrchestrationEvents",
                orchestratorMessages,
                timerMessages,
                continuedAsNewMessage);
            command.Parameters.AddTaskEventsParameter("@NewTaskEvents", outboundMessages);

            try
            {
                await SqlUtils.ExecuteNonQueryAsync(command, this.traceHelper, instance.InstanceId);
            }
            catch (SqlException e) when(SqlUtils.IsUniqueKeyViolation(e))
            {
                this.traceHelper.DuplicateExecutionDetected(instance, orchestrationState.Name);
                return;
            }

            // notify pollers that new messages may be available
            if (outboundMessages.Count > 0)
            {
                this.activityBackoffHelper.Reset();
            }

            if (orchestratorMessages.Count > 0 || timerMessages.Count > 0)
            {
                this.orchestrationBackoffHelper.Reset();
            }

            this.traceHelper.CheckpointCompleted(orchestrationState, sw);
        }
        public override async Task <TaskOrchestrationWorkItem?> LockNextTaskOrchestrationWorkItemAsync(
            TimeSpan receiveTimeout,
            CancellationToken cancellationToken)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();

            do
            {
                using SqlConnection connection = await this.GetAndOpenConnectionAsync(cancellationToken);

                using SqlCommand command = this.GetSprocCommand(connection, "dt._LockNextOrchestration");

                int      batchSize      = this.settings.WorkItemBatchSize;
                DateTime lockExpiration = DateTime.UtcNow.Add(this.settings.WorkItemLockTimeout);

                command.Parameters.Add("@BatchSize", SqlDbType.Int).Value            = batchSize;
                command.Parameters.Add("@LockedBy", SqlDbType.VarChar, 100).Value    = this.lockedByValue;
                command.Parameters.Add("@LockExpiration", SqlDbType.DateTime2).Value = lockExpiration;

                DbDataReader reader;

                try
                {
                    reader = await SqlUtils.ExecuteReaderAsync(
                        command,
                        this.traceHelper,
                        instanceId : null,
                        cancellationToken);
                }
                catch (Exception e)
                {
                    this.traceHelper.ProcessingError(e, new OrchestrationInstance());
                    throw;
                }

                using (reader)
                {
                    // Result #1: The list of control queue messages
                    int longestWaitTime      = 0;
                    var messages             = new List <TaskMessage>(capacity: batchSize);
                    var eventPayloadMappings = new Dictionary <HistoryEvent, Guid>(capacity: batchSize);
                    while (await reader.ReadAsync(cancellationToken))
                    {
                        TaskMessage message = reader.GetTaskMessage();
                        messages.Add(message);
                        Guid?payloadId = reader.GetPayloadId();
                        if (payloadId.HasValue)
                        {
                            // TODO: Need to understand what the payload behavior is for retry events
                            eventPayloadMappings.Add(message.Event, payloadId.Value);
                        }

                        longestWaitTime = Math.Max(longestWaitTime, reader.GetInt32("WaitTime"));
                    }

                    if (messages.Count == 0)
                    {
                        // TODO: Make this dynamic based on the number of readers
                        await this.orchestrationBackoffHelper.WaitAsync(cancellationToken);

                        continue;
                    }

                    this.orchestrationBackoffHelper.Reset();

                    // Result #2: The full event history for the locked instance
                    IList <HistoryEvent> history;
                    if (await reader.NextResultAsync(cancellationToken))
                    {
                        history = await ReadHistoryEventsAsync(reader, executionIdFilter : null, cancellationToken);
                    }
                    else
                    {
                        this.traceHelper.GenericWarning(
                            details: "Failed to read history from the database!",
                            instanceId: messages.FirstOrDefault(m => m.OrchestrationInstance?.InstanceId != null)?.OrchestrationInstance.InstanceId);
                        history = Array.Empty <HistoryEvent>();
                    }

                    var runtimeState = new OrchestrationRuntimeState(history);

                    string orchestrationName;
                    OrchestrationInstance instance;
                    if (runtimeState.ExecutionStartedEvent != null)
                    {
                        // This is an existing instance
                        orchestrationName = runtimeState.Name;
                        instance          = runtimeState.OrchestrationInstance;
                    }
                    else if (messages[0].Event is ExecutionStartedEvent startedEvent)
                    {
                        // This is a new manually-created instance
                        orchestrationName = startedEvent.Name;
                        instance          = startedEvent.OrchestrationInstance;
                    }
                    else if (Entities.AutoStart(messages[0].OrchestrationInstance.InstanceId, messages) &&
                             messages[0].Event is ExecutionStartedEvent autoStartedEvent)
                    {
                        // This is a new auto-start instance (e.g. Durable Entities)
                        orchestrationName = autoStartedEvent.Name;
                        instance          = autoStartedEvent.OrchestrationInstance;
                    }
                    else
                    {
                        // Don't know what to do with this message (TODO: Need to confirm behavior)
                        orchestrationName = "(Unknown)";
                        instance          = new OrchestrationInstance();
                    }

                    return(new ExtendedOrchestrationWorkItem(orchestrationName, instance)
                    {
                        InstanceId = messages[0].OrchestrationInstance.InstanceId,
                        LockedUntilUtc = lockExpiration,
                        NewMessages = messages,
                        OrchestrationRuntimeState = runtimeState,
                        EventPayloadMappings = eventPayloadMappings,
                    });
                }
            } while (stopwatch.Elapsed < receiveTimeout);

            return(null);
        }
        void verifyEventInput(string expectedHistoryEventInput, OrchestrationRuntimeState runtimeState)
        {
            var executionStartedEvent = runtimeState.Events[0] as ExecutionStartedEvent;

            Assert.AreEqual(expectedHistoryEventInput, executionStartedEvent?.Input);
        }
        /// <inheritdoc />
        public async Task CompleteTaskOrchestrationWorkItemAsync(
            TaskOrchestrationWorkItem workItem,
            OrchestrationRuntimeState newOrchestrationRuntimeState,
            IList <TaskMessage> outboundMessages,
            IList <TaskMessage> orchestratorMessages,
            IList <TaskMessage> timerMessages,
            TaskMessage continuedAsNewMessage,
            OrchestrationState orchestrationState)
        {
            if (this.partitionOrchestrationManager == null || this.redisConnection == null)
            {
                await StartAsync();
            }
            string orchestrationId = workItem.InstanceId;
            RedisTransactionBuilder transaction = this.partitionOrchestrationManager.CreateExistingOrchestrationTransaction(orchestrationId);

            List <string> events = newOrchestrationRuntimeState.Events.Select(histEvent => histEvent as TaskCompletedEvent)
                                   .Where(taskCompletedEvent => taskCompletedEvent != null)
                                   .OrderBy(task => task.TaskScheduledId)
                                   .Select(TaskCompletedEvent => $"{{\"id\": {TaskCompletedEvent.TaskScheduledId}, \"Result\": {TaskCompletedEvent.Result}}}")
                                   .ToList();
            string logMessage = "Current events processed: " + string.Join(",", events);

            await this.logger.LogAsync(logMessage);

            transaction.SetOrchestrationRuntimeState(orchestrationId, newOrchestrationRuntimeState);

            foreach (TaskMessage outboundMessage in outboundMessages)
            {
                transaction.SendActivityMessage(outboundMessage);
            }

            foreach (TaskMessage message in orchestratorMessages)
            {
                transaction.SendControlQueueMessage(message);
            }

            if (continuedAsNewMessage != null)
            {
                transaction.SendControlQueueMessage(continuedAsNewMessage);
            }

            // TODO send timer messages in transaction

            transaction.AddOrchestrationStateToHistory(orchestrationId: orchestrationId,
                                                       state: orchestrationState);

            transaction.RemoveItemsFromOrchestrationQueue(orchestrationId, workItem.NewMessages.Count);

            bool transactionSucceeded = await transaction.CommitTransactionAsync();

            if (transactionSucceeded)
            {
                logMessage = $"Succeeded in transaction of finishing task orchestration item: execution id={workItem.OrchestrationRuntimeState.OrchestrationInstance.ExecutionId}, numMessagesProcessed: {workItem.NewMessages.Count}, numOutBoundMessages: {outboundMessages.Count}, numOrchMessages: {orchestratorMessages.Count}";
            }
            else
            {
                logMessage = $"Failed in transaction of finishing task orchestration item: execution id={workItem.OrchestrationRuntimeState.OrchestrationInstance.ExecutionId}, numMessagesProcessed: {workItem.NewMessages.Count}, numOutBoundMessages: {outboundMessages.Count}, numOrchMessages: {orchestratorMessages.Count}";
            }
            await this.logger.LogAsync(logMessage);
        }
        public async Task UpdateSessionState(ITransaction transaction, OrchestrationInstance instance, OrchestrationRuntimeState newSessionState)
        {
            var sessionStateEvents = newSessionState?.Events.ToImmutableList();
            var result             = PersistentSession.Create(instance, sessionStateEvents);

            await this.Store.SetAsync(transaction, instance.InstanceId, result);
        }
 public bool IsMaxMessageCountExceeded(int currentMessageCount, OrchestrationRuntimeState runtimeState)
 {
     return(false);
 }
Exemplo n.º 17
0
        static async Task Main(string[] args)
        {
            //Use Azurite emulator
            string storageConnectionString = "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;" +
                                             "BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1";
            string taskHubName = "Hello";

            var settings = new AzureStorageOrchestrationServiceSettings();

            settings.StorageConnectionString      = storageConnectionString;
            settings.TaskHubName                  = taskHubName;
            settings.UseDataContractSerialization = true;

            var orchestrationServiceAndClient = new AzureStorageOrchestrationService(settings);
            await orchestrationServiceAndClient.CreateIfNotExistsAsync();

            var taskHubClient = new TaskHubClient(orchestrationServiceAndClient);
            var taskHub       = new TaskHubWorker(orchestrationServiceAndClient);

            // add instance
            _ = Task.Run(async() =>
            {
                OrchestrationInstance ins = await taskHubClient.CreateOrchestrationInstanceAsync(typeof(HelloOrchestration), "");
            });

            // add worker
            try
            {
                taskHub.AddTaskOrchestrations(
                    typeof(HelloOrchestration)
                    );

                taskHub.AddTaskActivities(typeof(HelloTask));
                taskHub.AddOrchestrationDispatcherMiddleware(async(context, next) =>
                {
                    OrchestrationRuntimeState runtimeState = context.GetProperty <OrchestrationRuntimeState>();
                    var customInstance      = OrchestrationInstanceEx.Initialize(runtimeState);
                    customInstance.Dic["a"] = "a";
                    customInstance.Dic["b"] = "b";
                    customInstance.Dic["c"] = "c";
                    context.SetProperty <OrchestrationInstance>(customInstance);

                    await next();
                });

                taskHub.AddOrchestrationDispatcherMiddleware(async(context, next) =>
                {
                    var customInstance = OrchestrationInstanceEx.Get(context.GetProperty <OrchestrationInstance>());
                    context.SetProperty <OrchestrationInstance>(customInstance);

                    //Dic data can get here. But missed in HelloOrchestration context and ActivityDispatcherMiddleware

                    await next();
                });

                taskHub.AddActivityDispatcherMiddleware(async(context, next) =>
                {
                    var customInstance = OrchestrationInstanceEx.Get(context.GetProperty <OrchestrationInstance>());
                    context.SetProperty <OrchestrationInstance>(customInstance);

                    //Dic data missed

                    await next();
                });

                await taskHub.StartAsync();

                //Console.WriteLine("Press any key to quit.");
                Console.ReadLine();
                taskHub.StopAsync(true).Wait();
            }
            catch (Exception e)
            {
                // silently eat any unhandled exceptions.
                Console.WriteLine($"worker exception: {e}");
            }
        }
        public async Task CompleteTaskOrchestrationWorkItemAsync(
            TaskOrchestrationWorkItem workItem,
            OrchestrationRuntimeState newOrchestrationRuntimeState,
            IList <TaskMessage> outboundMessages,
            IList <TaskMessage> orchestratorMessages,
            IList <TaskMessage> timerMessages,
            TaskMessage continuedAsNewMessage,
            OrchestrationState orchestrationState)
        {
            using (var dbContext = _dbContextFactory())
            {
                var session = workItem.Session as EFCoreOrchestrationSession;

                // Create child orchestrations
                foreach (var executionStartedEvent in orchestratorMessages.Select(m => m.Event).OfType <ExecutionStartedEvent>())
                {
                    var childInstance = _instanceMapper.CreateInstance(executionStartedEvent);
                    await dbContext.Instances.AddAsync(childInstance);

                    var childRuntimeState = new OrchestrationRuntimeState(new[] { executionStartedEvent });
                    var childExecution    = _executionMapper.CreateExecution(childRuntimeState);
                    await dbContext.Executions.AddAsync(childExecution);
                }

                var orchestrationQueueName = QueueMapper.ToQueueName(orchestrationState.Name, orchestrationState.Version);

                var knownQueues = new Dictionary <string, string>
                {
                    [orchestrationState.OrchestrationInstance.InstanceId] = orchestrationQueueName
                };

                if (orchestrationState.ParentInstance != null)
                {
                    knownQueues[orchestrationState.ParentInstance.OrchestrationInstance.InstanceId] = QueueMapper.ToQueueName(orchestrationState.ParentInstance.Name, orchestrationState.ParentInstance.Version);
                }

                // Write messages
                var activityMessages = outboundMessages
                                       .Select(m => _activityMessageMapper.CreateActivityMessage(m, orchestrationQueueName))
                                       .ToArray();
                var orchestatorMessages = await orchestratorMessages
                                          .Select((m, i) => _orchestrationMessageMapper.CreateOrchestrationMessageAsync(m, i, dbContext, knownQueues))
                                          .WhenAllSerial();

                var timerOrchestrationMessages = await timerMessages
                                                 .Select((m, i) => _orchestrationMessageMapper.CreateOrchestrationMessageAsync(m, i, dbContext, knownQueues))
                                                 .WhenAllSerial();

                var continuedAsNewOrchestrationMessage = continuedAsNewMessage != null
                    ? await _orchestrationMessageMapper.CreateOrchestrationMessageAsync(continuedAsNewMessage, 0, dbContext, knownQueues)
                    : null;

                await dbContext.ActivityMessages.AddRangeAsync(activityMessages);

                await dbContext.OrchestrationMessages.AddRangeAsync(orchestatorMessages);

                await dbContext.OrchestrationMessages.AddRangeAsync(timerOrchestrationMessages);

                if (continuedAsNewOrchestrationMessage != null)
                {
                    await dbContext.OrchestrationMessages.AddAsync(continuedAsNewOrchestrationMessage);
                }

                // Remove executed messages
                dbContext.AttachRange(session.Messages);
                dbContext.OrchestrationMessages.RemoveRange(session.Messages);

                // Update instance
                var instance = session.Instance;
                dbContext.Instances.Attach(instance);
                _instanceMapper.UpdateInstance(instance, newOrchestrationRuntimeState);

                // Update current execution
                EnrichNewEventsInput(workItem.OrchestrationRuntimeState, outboundMessages, orchestratorMessages);
                session.Execution = await SaveExecutionAsync(dbContext, workItem.OrchestrationRuntimeState, session.Execution);

                // Update new execution
                if (newOrchestrationRuntimeState != workItem.OrchestrationRuntimeState)
                {
                    EnrichNewEventsInput(newOrchestrationRuntimeState, outboundMessages, orchestratorMessages);
                    session.Execution = await SaveExecutionAsync(dbContext, newOrchestrationRuntimeState);
                }

                await dbContext.SaveChangesAsync();

                session.RuntimeState = newOrchestrationRuntimeState;
                session.ClearMessages();
            }
        }
        /// <inheritdoc />
        public Task CompleteTaskOrchestrationWorkItemAsync(
            TaskOrchestrationWorkItem workItem,
            OrchestrationRuntimeState newOrchestrationRuntimeState,
            IList <TaskMessage> outboundMessages,
            IList <TaskMessage> orchestratorMessages,
            IList <TaskMessage> workItemTimerMessages,
            TaskMessage continuedAsNewMessage,
            OrchestrationState state)
        {
            lock (this.thisLock)
            {
                this.orchestratorQueue.CompleteSession(
                    workItem.InstanceId,
                    newOrchestrationRuntimeState != null ?
                    this.SerializeOrchestrationRuntimeState(newOrchestrationRuntimeState) : null,
                    orchestratorMessages,
                    continuedAsNewMessage
                    );

                if (outboundMessages != null)
                {
                    foreach (TaskMessage m in outboundMessages)
                    {
                        // AFFANDAR : TODO : make async
                        this.workerQueue.SendMessageAsync(m);
                    }
                }

                if (workItemTimerMessages != null)
                {
                    lock (this.timerLock)
                    {
                        foreach (TaskMessage m in workItemTimerMessages)
                        {
                            this.timerMessages.Add(m);
                        }
                    }
                }

                if (state != null)
                {
                    Dictionary <string, OrchestrationState> ed;

                    if (!this.instanceStore.TryGetValue(workItem.InstanceId, out ed))
                    {
                        ed = new Dictionary <string, OrchestrationState>();
                        this.instanceStore[workItem.InstanceId] = ed;
                    }

                    ed[workItem.OrchestrationRuntimeState.OrchestrationInstance.ExecutionId] = state;

                    // signal any waiters waiting on instanceid_executionid or just the latest instanceid_
                    TaskCompletionSource <OrchestrationState> tcs  = null;
                    TaskCompletionSource <OrchestrationState> tcs1 = null;

                    if (state.OrchestrationStatus == OrchestrationStatus.Running ||
                        state.OrchestrationStatus == OrchestrationStatus.Pending)
                    {
                        return(Task.FromResult(0));
                    }

                    string key = workItem.OrchestrationRuntimeState.OrchestrationInstance.InstanceId + "_" +
                                 workItem.OrchestrationRuntimeState.OrchestrationInstance.ExecutionId;

                    string key1 = workItem.OrchestrationRuntimeState.OrchestrationInstance.InstanceId + "_";

                    var tasks = new List <Task>();


                    if (this.orchestrationWaiters.TryGetValue(key, out tcs))
                    {
                        tasks.Add(Task.Run(() => tcs.TrySetResult(state)));
                    }

                    // for instance id level waiters, we will not consider ContinueAsNew as a terminal state because
                    // the high level orchestration is still ongoing
                    if (state.OrchestrationStatus != OrchestrationStatus.ContinuedAsNew &&
                        this.orchestrationWaiters.TryGetValue(key1, out tcs1))
                    {
                        tasks.Add(Task.Run(() => tcs1.TrySetResult(state)));
                    }

                    if (tasks.Count > 0)
                    {
                        Task.WaitAll(tasks.ToArray());
                    }
                }
            }

            return(Task.FromResult(0));
        }
        public RedisTransactionBuilder SetOrchestrationRuntimeState(string orchestrationId, OrchestrationRuntimeState state)
        {
            if (this.partition == null)
            {
                throw new ArgumentNullException($"Cannot call {nameof(SetOrchestrationRuntimeState)} without a partition set.");
            }
            string orchestrationStateKey = RedisKeyNameResolver.GetOrchestrationRuntimeStateHashKey(this.taskHub, this.partition);

            // Do not want to serialize new events;
            state.NewEvents.Clear();
            string stateJson = RedisSerializer.SerializeObject(state.Events);

            transaction.HashSetAsync(orchestrationStateKey, orchestrationId, stateJson);
            return(this);
        }
Exemplo n.º 21
0
        /// <inheritdoc />
        public override async Task UpdateStateAsync(OrchestrationRuntimeState runtimeState, string instanceId, string executionId)
        {
            int estimatedBytes             = 0;
            IList <HistoryEvent> newEvents = runtimeState.NewEvents;
            IList <HistoryEvent> allEvents = runtimeState.Events;

            var newEventListBuffer = new StringBuilder(4000);
            var historyEventBatch  = new TableBatchOperation();

            EventType?orchestratorEventType = null;

            string eTagValue = this.GetETagValue(instanceId);

            DynamicTableEntity orchestrationInstanceUpdate = new DynamicTableEntity(instanceId, "")
            {
                Properties =
                {
                    ["CustomStatus"]    = new EntityProperty(runtimeState.Status),
                    ["ExecutionId"]     = new EntityProperty(executionId),
                    ["LastUpdatedTime"] = new EntityProperty(newEvents.Last().Timestamp),
                }
            };

            for (int i = 0; i < newEvents.Count; i++)
            {
                HistoryEvent       historyEvent = newEvents[i];
                DynamicTableEntity entity       = this.tableEntityConverter.ConvertToTableEntity(historyEvent);

                await this.CompressLargeMessageAsync(entity);

                newEventListBuffer.Append(historyEvent.EventType.ToString()).Append(',');

                // The row key is the sequence number, which represents the chronological ordinal of the event.
                long sequenceNumber = i + (allEvents.Count - newEvents.Count);
                entity.RowKey       = sequenceNumber.ToString("X16");
                entity.PartitionKey = instanceId;
                entity.Properties["ExecutionId"] = new EntityProperty(executionId);

                // Replacement can happen if the orchestration episode gets replayed due to a commit failure in one of the steps below.
                historyEventBatch.InsertOrReplace(entity);

                // Keep track of the byte count to ensure we don't hit the 4 MB per-batch maximum
                estimatedBytes += GetEstimatedByteCount(entity);

                // Monitor for orchestration instance events
                switch (historyEvent.EventType)
                {
                case EventType.ExecutionStarted:
                    orchestratorEventType = historyEvent.EventType;
                    ExecutionStartedEvent executionStartedEvent = (ExecutionStartedEvent)historyEvent;
                    orchestrationInstanceUpdate.Properties["Name"]          = new EntityProperty(executionStartedEvent.Name);
                    orchestrationInstanceUpdate.Properties["Version"]       = new EntityProperty(executionStartedEvent.Version);
                    orchestrationInstanceUpdate.Properties["CreatedTime"]   = new EntityProperty(executionStartedEvent.Timestamp);
                    orchestrationInstanceUpdate.Properties["RuntimeStatus"] = new EntityProperty(OrchestrationStatus.Running.ToString());
                    this.SetTablePropertyForMessage(entity, orchestrationInstanceUpdate, InputProperty, InputProperty, executionStartedEvent.Input);
                    break;

                case EventType.ExecutionCompleted:
                    orchestratorEventType = historyEvent.EventType;
                    ExecutionCompletedEvent executionCompleted = (ExecutionCompletedEvent)historyEvent;
                    this.SetTablePropertyForMessage(entity, orchestrationInstanceUpdate, ResultProperty, OutputProperty, executionCompleted.Result);
                    orchestrationInstanceUpdate.Properties["RuntimeStatus"] = new EntityProperty(executionCompleted.OrchestrationStatus.ToString());
                    break;

                case EventType.ExecutionTerminated:
                    orchestratorEventType = historyEvent.EventType;
                    ExecutionTerminatedEvent executionTerminatedEvent = (ExecutionTerminatedEvent)historyEvent;
                    this.SetTablePropertyForMessage(entity, orchestrationInstanceUpdate, InputProperty, OutputProperty, executionTerminatedEvent.Input);
                    orchestrationInstanceUpdate.Properties["RuntimeStatus"] = new EntityProperty(OrchestrationStatus.Terminated.ToString());
                    break;

                case EventType.ContinueAsNew:
                    orchestratorEventType = historyEvent.EventType;
                    ExecutionCompletedEvent executionCompletedEvent = (ExecutionCompletedEvent)historyEvent;
                    this.SetTablePropertyForMessage(entity, orchestrationInstanceUpdate, ResultProperty, OutputProperty, executionCompletedEvent.Result);
                    orchestrationInstanceUpdate.Properties["RuntimeStatus"] = new EntityProperty(OrchestrationStatus.ContinuedAsNew.ToString());
                    break;
                }

                // Table storage only supports inserts of up to 100 entities at a time or 4 MB at a time.
                if (historyEventBatch.Count == 99 || estimatedBytes > 3 * 1024 * 1024 /* 3 MB */)
                {
                    eTagValue = await this.UploadHistoryBatch(
                        instanceId,
                        executionId,
                        historyEventBatch,
                        newEventListBuffer,
                        newEvents.Count,
                        estimatedBytes,
                        eTagValue);

                    // Reset local state for the next batch
                    newEventListBuffer.Clear();
                    historyEventBatch.Clear();
                    estimatedBytes = 0;
                }
            }

            // First persistence step is to commit history to the history table. Messages must come after.
            if (historyEventBatch.Count > 0)
            {
                eTagValue = await this.UploadHistoryBatch(
                    instanceId,
                    executionId,
                    historyEventBatch,
                    newEventListBuffer,
                    newEvents.Count,
                    estimatedBytes,
                    eTagValue);
            }

            if (orchestratorEventType == EventType.ExecutionCompleted ||
                orchestratorEventType == EventType.ExecutionFailed ||
                orchestratorEventType == EventType.ExecutionTerminated)
            {
                this.eTagValues.TryRemove(instanceId, out _);
            }
            else
            {
                this.eTagValues[instanceId] = eTagValue;
            }

            Stopwatch orchestrationInstanceUpdateStopwatch = Stopwatch.StartNew();

            await this.instancesTable.ExecuteAsync(TableOperation.InsertOrMerge(orchestrationInstanceUpdate));

            this.stats.StorageRequests.Increment();
            this.stats.TableEntitiesWritten.Increment();

            AnalyticsEventSource.Log.InstanceStatusUpdate(
                this.storageAccountName,
                this.taskHubName,
                instanceId,
                executionId,
                orchestratorEventType?.ToString() ?? string.Empty,
                orchestrationInstanceUpdateStopwatch.ElapsedMilliseconds,
                Utils.ExtensionVersion);
        }
Exemplo n.º 22
0
 /// <inheritdoc />
 public abstract Task <string> UpdateStateAsync(OrchestrationRuntimeState runtimeState, string instanceId, string executionId, string eTag);
Exemplo n.º 23
0
        private async Task OrchestrationMiddleware(DispatchMiddlewareContext dispatchContext, Func <Task> next)
        {
            TaskOrchestrationShim shim = dispatchContext.GetProperty <TaskOrchestration>() as TaskOrchestrationShim;

            if (shim == null)
            {
                // This is not an orchestration - skip.
                await next();

                return;
            }

            DurableOrchestrationContext context = (DurableOrchestrationContext)shim.Context;

            OrchestrationRuntimeState orchestrationRuntimeState = dispatchContext.GetProperty <OrchestrationRuntimeState>();

            if (orchestrationRuntimeState.ParentInstance != null)
            {
                context.ParentInstanceId = orchestrationRuntimeState.ParentInstance.OrchestrationInstance.InstanceId;
            }

            context.InstanceId  = orchestrationRuntimeState.OrchestrationInstance.InstanceId;
            context.ExecutionId = orchestrationRuntimeState.OrchestrationInstance.ExecutionId;
            context.IsReplaying = orchestrationRuntimeState.ExecutionStartedEvent.IsPlayed;
            context.History     = orchestrationRuntimeState.Events;
            context.RawInput    = orchestrationRuntimeState.Input;

            var info = shim.GetFunctionInfo();

            if (info == null)
            {
                string message = this.GetInvalidOrchestratorFunctionMessage(context.FunctionName);
                this.TraceHelper.ExtensionWarningEvent(
                    this.Options.HubName,
                    orchestrationRuntimeState.Name,
                    orchestrationRuntimeState.OrchestrationInstance.InstanceId,
                    message);
                throw new InvalidOperationException(message);
            }

            // 1. Start the functions invocation pipeline (billing, logging, bindings, and timeout tracking).
            FunctionResult result = await info.Executor.TryExecuteAsync(
                new TriggeredFunctionData
            {
                TriggerValue = context,

#pragma warning disable CS0618 // Approved for use by this extension
                InvokeHandler = async userCodeInvoker =>
                {
                    // 2. Configure the shim with the inner invoker to execute the user code.
                    shim.SetFunctionInvocationCallback(userCodeInvoker);

                    // 3. Move to the next stage of the DTFx pipeline to trigger the orchestrator shim.
                    await next();

                    // 4. If an activity failed, indicate to the functions Host that this execution failed via an exception
                    if (context.IsCompleted && context.OrchestrationException != null)
                    {
                        context.OrchestrationException.Throw();
                    }
                },
#pragma warning restore CS0618
            },
                CancellationToken.None);

            if (!context.IsCompleted)
            {
                this.TraceHelper.FunctionAwaited(
                    context.HubName,
                    context.Name,
                    FunctionType.Orchestrator,
                    context.InstanceId,
                    context.IsReplaying);
            }

            if (context.IsCompleted &&
                context.PreserveUnprocessedEvents)
            {
                // Reschedule any unprocessed external events so that they can be picked up
                // in the next iteration.
                context.RescheduleBufferedExternalEvents();
            }

            await context.RunDeferredTasks();
        }
Exemplo n.º 24
0
 public virtual bool IsMaxMessageCountExceeded(
     int currentMessageCount,
     OrchestrationRuntimeState runtimeState) => false;
Exemplo n.º 25
0
        private async Task EntityMiddleware(DispatchMiddlewareContext dispatchContext, Func <Task> next)
        {
            var entityShim = dispatchContext.GetProperty <TaskOrchestration>() as TaskEntityShim;

            if (entityShim == null)
            {
                // This is not an entity - skip.
                await next();

                return;
            }

            OrchestrationRuntimeState runtimeState  = dispatchContext.GetProperty <OrchestrationRuntimeState>();
            DurableEntityContext      entityContext = (DurableEntityContext)entityShim.Context;

            entityContext.InstanceId  = runtimeState.OrchestrationInstance.InstanceId;
            entityContext.ExecutionId = runtimeState.OrchestrationInstance.ExecutionId;
            entityContext.History     = runtimeState.Events;
            entityContext.RawInput    = runtimeState.Input;

            try
            {
                // 1. First time through the history
                // we count events, add any under-lock op to the batch, and process lock releases
                foreach (HistoryEvent e in runtimeState.Events)
                {
                    switch (e.EventType)
                    {
                    case EventType.ExecutionStarted:
                        entityShim.Rehydrate(runtimeState.Input);
                        break;

                    case EventType.EventRaised:
                        EventRaisedEvent eventRaisedEvent = (EventRaisedEvent)e;

                        this.TraceHelper.DeliveringEntityMessage(
                            entityContext.InstanceId,
                            entityContext.ExecutionId,
                            e.EventId,
                            eventRaisedEvent.Name,
                            eventRaisedEvent.Input);

                        entityShim.NumberEventsToReceive++;

                        if (EntityMessageEventNames.IsRequestMessage(eventRaisedEvent.Name))
                        {
                            // we are receiving an operation request or a lock request
                            var requestMessage = this.DataConverter.Deserialize <RequestMessage>(eventRaisedEvent.Input);

                            IEnumerable <RequestMessage> deliverNow;

                            if (requestMessage.ScheduledTime.HasValue)
                            {
                                // messages with a scheduled time are always delivered immediately
                                deliverNow = new RequestMessage[] { requestMessage };
                            }
                            else
                            {
                                // run this through the message sorter to help with reordering and duplicate filtering
                                deliverNow = entityContext.State.MessageSorter.ReceiveInOrder(requestMessage, entityContext.EntityMessageReorderWindow);
                            }

                            foreach (var message in deliverNow)
                            {
                                if (entityContext.State.LockedBy == message.ParentInstanceId)
                                {
                                    // operation requests from the lock holder are processed immediately
                                    entityShim.AddOperationToBatch(message);
                                }
                                else
                                {
                                    // others go to the back of the queue
                                    entityContext.State.Enqueue(message);
                                }
                            }
                        }
                        else
                        {
                            // we are receiving a lock release
                            var message = this.DataConverter.Deserialize <ReleaseMessage>(eventRaisedEvent.Input);

                            if (entityContext.State.LockedBy == message.ParentInstanceId)
                            {
                                this.TraceHelper.EntityLockReleased(
                                    entityContext.HubName,
                                    entityContext.Name,
                                    entityContext.InstanceId,
                                    message.ParentInstanceId,
                                    message.LockRequestId,
                                    isReplay: false);

                                entityContext.State.LockedBy = null;
                            }
                        }

                        break;
                    }
                }

                // 2. We add as many requests from the queue to the batch as possible (stopping at lock requests)
                while (entityContext.State.LockedBy == null &&
                       entityContext.State.TryDequeue(out var request))
                {
                    if (request.IsLockRequest)
                    {
                        entityShim.AddLockRequestToBatch(request);
                        entityContext.State.LockedBy = request.ParentInstanceId;
                    }
                    else
                    {
                        entityShim.AddOperationToBatch(request);
                    }
                }
            }
            catch (Exception e)
            {
                entityContext.CaptureInternalError(e);
            }

            // 3. Start the functions invocation pipeline (billing, logging, bindings, and timeout tracking).
            FunctionResult result = await entityShim.GetFunctionInfo().Executor.TryExecuteAsync(
                new TriggeredFunctionData
            {
                TriggerValue = entityShim.Context,

#pragma warning disable CS0618 // Approved for use by this extension
                InvokeHandler = async userCodeInvoker =>
                {
                    entityShim.SetFunctionInvocationCallback(userCodeInvoker);

                    // 3. Run all the operations in the batch
                    if (entityContext.InternalError == null)
                    {
                        try
                        {
                            await entityShim.ExecuteBatch();
                        }
                        catch (Exception e)
                        {
                            entityContext.CaptureInternalError(e);
                        }
                    }

                    // 4. Run the DTFx orchestration to persist the effects,
                    // send the outbox, and continue as new
                    await next();

                    // 5. If there were internal or application errors, indicate to the functions host
                    entityContext.ThrowInternalExceptionIfAny();
                    entityContext.ThrowApplicationExceptionsIfAny();
                },
#pragma warning restore CS0618
            },
                CancellationToken.None);

            await entityContext.RunDeferredTasks();

            // If there were internal errors, do not commit the batch, but instead rethrow
            // here so DTFx can abort the batch and back off the work item
            entityContext.ThrowInternalExceptionIfAny();
        }
Exemplo n.º 26
0
 /// <inheritdoc/>
 public bool IsMaxMessageCountExceeded(int currentMessageCount, OrchestrationRuntimeState runtimeState)
 {
     return(this.GetOrchestrationService().IsMaxMessageCountExceeded(currentMessageCount, runtimeState));
 }
 public Task CompleteTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkItem workItem, OrchestrationRuntimeState newOrchestrationRuntimeState, IList<TaskMessage> outboundMessages, IList<TaskMessage> orchestratorMessages, IList<TaskMessage> timerMessages, TaskMessage continuedAsNewMessage, OrchestrationState orchestrationState) {
     return this.OrchestrationService.CompleteTaskOrchestrationWorkItemAsync(workItem, newOrchestrationRuntimeState, outboundMessages, orchestratorMessages, timerMessages, continuedAsNewMessage, orchestrationState);
 }