async Task DequeueLoop(string partitionId, ControlQueue controlQueue, CancellationToken cancellationToken) { this.settings.Logger.PartitionManagerInfo( this.storageAccountName, this.settings.TaskHubName, this.settings.WorkerId, partitionId, $"Started listening for messages on queue {controlQueue.Name}."); while (!controlQueue.IsReleased) { try { // Every dequeue operation has a common trace ID so that batches of dequeued messages can be correlated together. // Both the dequeue traces and the processing traces will share the same "related" trace activity ID. Guid traceActivityId = AzureStorageOrchestrationService.StartNewLogicalTraceScope(useExisting: false); // This will block until either new messages arrive or the queue is released. IReadOnlyList <MessageData> messages = await controlQueue.GetMessagesAsync(cancellationToken); if (messages.Count > 0) { // De-dupe any execution started messages IEnumerable <MessageData> filteredMessages = await this.DedupeExecutionStartedMessagesAsync( controlQueue, messages, traceActivityId, cancellationToken); this.AddMessageToPendingOrchestration(controlQueue, filteredMessages, traceActivityId, cancellationToken); } } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { // shutting down break; } catch (Exception e) { this.settings.Logger.PartitionManagerWarning( this.storageAccountName, this.settings.TaskHubName, this.settings.WorkerId, partitionId, $"Exception in the dequeue loop for control queue {controlQueue.Name}. Exception: {e}"); Thread.Sleep(TimeSpan.FromSeconds(1)); } } this.settings.Logger.PartitionManagerInfo( this.storageAccountName, this.settings.TaskHubName, this.settings.WorkerId, partitionId, $"Stopped listening for messages on queue {controlQueue.Name}."); }
async Task DequeueLoop(string partitionId, ControlQueue controlQueue, CancellationToken cancellationToken) { this.settings.Logger.PartitionManagerInfo( this.storageAccountName, this.settings.TaskHubName, this.settings.WorkerId, partitionId, $"Started listening for messages on queue {controlQueue.Name}."); try { while (!controlQueue.IsReleased) { // Every dequeue operation has a common trace ID so that batches of dequeued messages can be correlated together. // Both the dequeue traces and the processing traces will share the same "related" trace activity ID. Guid traceActivityId = AzureStorageOrchestrationService.StartNewLogicalTraceScope(useExisting: false); // This will block until either new messages arrive or the queue is released. IReadOnlyList <MessageData> messages = await controlQueue.GetMessagesAsync(cancellationToken); // De-dupe any execution started messages messages = this.FilterOutExecutionStartedForDedupeValidation(controlQueue, messages, traceActivityId, cancellationToken); if (messages.Count > 0) { this.AddMessageToPendingOrchestration(controlQueue, messages, traceActivityId, cancellationToken); } } } finally { this.settings.Logger.PartitionManagerInfo( this.storageAccountName, this.settings.TaskHubName, this.settings.WorkerId, partitionId, $"Stopped listening for messages on queue {controlQueue.Name}."); } }
async void DequeueLoop(string partitionId, ControlQueue controlQueue, CancellationToken cancellationToken) { AnalyticsEventSource.Log.PartitionManagerInfo( this.storageAccountName, this.settings.TaskHubName, this.settings.WorkerId, partitionId, $"Started listening for messages on queue {controlQueue.Name}.", Utils.ExtensionVersion); try { while (!controlQueue.IsReleased) { // Every dequeue operation has a common trace ID so that batches of dequeued messages can be correlated together. // Both the dequeue traces and the processing traces will share the same "related" trace activity ID. Guid traceActivityId = AzureStorageOrchestrationService.StartNewLogicalTraceScope(); // This will block until either new messages arrive or the queue is released. IReadOnlyList <MessageData> messages = await controlQueue.GetMessagesAsync(cancellationToken); if (messages.Count > 0) { this.AddMessageToPendingOrchestration(controlQueue, messages, traceActivityId, cancellationToken); } } } finally { AnalyticsEventSource.Log.PartitionManagerInfo( this.storageAccountName, this.settings.TaskHubName, this.settings.WorkerId, partitionId, $"Stopped listening for messages on queue {controlQueue.Name}.", Utils.ExtensionVersion); } }
public async Task <OrchestrationSession> GetNextSessionAsync(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { // This call will block until: // 1) a batch of messages has been received for a particular instance and // 2) the history for that instance has been fetched LinkedListNode <PendingMessageBatch> node = await this.readyForProcessingQueue.DequeueAsync(cancellationToken); lock (this.messageAndSessionLock) { PendingMessageBatch nextBatch = node.Value; this.pendingOrchestrationMessageBatches.Remove(node); if (!this.activeOrchestrationSessions.TryGetValue(nextBatch.OrchestrationInstanceId, out var existingSession)) { OrchestrationInstance instance = nextBatch.OrchestrationState.OrchestrationInstance ?? new OrchestrationInstance { InstanceId = nextBatch.OrchestrationInstanceId, ExecutionId = nextBatch.OrchestrationExecutionId, }; Guid traceActivityId = AzureStorageOrchestrationService.StartNewLogicalTraceScope(useExisting: true); OrchestrationSession session = new OrchestrationSession( this.settings, this.storageAccountName, instance, nextBatch.ControlQueue, nextBatch.Messages, nextBatch.OrchestrationState, nextBatch.ETag, nextBatch.LastCheckpointTime, this.settings.ExtendedSessionIdleTimeout, traceActivityId); this.activeOrchestrationSessions.Add(instance.InstanceId, session); return(session); } else if (nextBatch.OrchestrationExecutionId == existingSession.Instance.ExecutionId) { // there is already an active session with the same execution id. // The session might be waiting for more messages. If it is, signal them. existingSession.AddOrReplaceMessages(node.Value.Messages); } else { // A message arrived for a different generation of an existing orchestration instance. // Put it back into the ready queue so that it can be processed once the current generation // is done executing. if (this.readyForProcessingQueue.Count == 0) { // To avoid a tight dequeue loop, delay for a bit before putting this node back into the queue. // This is only necessary when the queue is empty. The main dequeue thread must not be blocked // by this delay, which is why we use Task.Delay(...).ContinueWith(...) instead of await. Task.Delay(millisecondsDelay: 200).ContinueWith(_ => { lock (this.messageAndSessionLock) { this.pendingOrchestrationMessageBatches.AddLast(node); this.readyForProcessingQueue.Enqueue(node); } }); } else { this.pendingOrchestrationMessageBatches.AddLast(node); this.readyForProcessingQueue.Enqueue(node); } } } } return(null); }