async Task SendMessagesPump() { // TODO: 6099918 - Update StoringAsyncEndpointExecutor message pump to process messages by priority try { Events.StartSendMessagesPump(this); IMessageIterator iterator = this.messageStore.GetMessageIterator(this.Endpoint.Id, this.checkpointer.Offset + 1); int batchSize = this.options.BatchSize * this.Endpoint.FanOutFactor; var storeMessagesProvider = new StoreMessagesProvider(iterator, batchSize); while (!this.cts.IsCancellationRequested) { try { await this.hasMessagesInQueue.WaitAsync(this.options.BatchTimeout); IMessage[] messages = await storeMessagesProvider.GetMessages(); if (messages.Length > 0) { await this.ProcessMessages(messages); Events.SendMessagesSuccess(this, messages); MetricsV0.DrainedCountIncrement(this.Endpoint.Id, messages.Length); } else { // If store has no messages, then reset the hasMessagesInQueue flag. this.hasMessagesInQueue.Reset(); } } catch (Exception ex) { Events.SendMessagesError(this, ex); // Swallow exception and keep trying. } } } catch (Exception ex) { Events.SendMessagesPumpFailure(this, ex); } }
async Task SendMessagesPump() { try { Events.StartSendMessagesPump(this); int batchSize = this.options.BatchSize * this.Endpoint.FanOutFactor; // Keep the stores and prefetchers for each priority loaded // for the duration of the pump var messageProviderPairs = new Dictionary <uint, (IMessageIterator, StoreMessagesProvider)>(); // Outer loop to maintain the message pump until the executor shuts down while (!this.cts.IsCancellationRequested) { try { await this.hasMessagesInQueue.WaitAsync(this.options.BatchTimeout); ImmutableDictionary <uint, EndpointExecutorFsm> snapshot = this.prioritiesToFsms; bool haveMessagesRemaining = false; uint[] orderedPriorities = snapshot.Keys.OrderBy(k => k).ToArray(); // Iterate through all the message queues in priority order foreach (uint priority in orderedPriorities) { // Also check for cancellation in every inner loop, // since it could take time to send a batch of messages if (this.cts.IsCancellationRequested) { break; } EndpointExecutorFsm fsm = snapshot[priority]; // Update the lastUsedFsm to be the current FSM this.lastUsedFsm = fsm; (IMessageIterator, StoreMessagesProvider)pair; if (!messageProviderPairs.TryGetValue(priority, out pair)) { // Create and cache a new pair for the message provider // so we can reuse it every loop pair.Item1 = this.messageStore.GetMessageIterator(GetMessageQueueId(this.Endpoint.Id, priority), fsm.Checkpointer.Offset + 1); pair.Item2 = new StoreMessagesProvider(pair.Item1, batchSize); messageProviderPairs.Add(priority, pair); } StoreMessagesProvider storeMessagesProvider = pair.Item2; IMessage[] messages = await storeMessagesProvider.GetMessages(); if (messages.Length > 0) { // Tag the message with the priority that we're currently // processing, so it can be used by metrics later foreach (IMessage msg in messages) { msg.ProcessedPriority = priority; } Events.ProcessingMessages(this, messages, priority); await this.ProcessMessages(messages, fsm); Events.SendMessagesSuccess(this, messages, priority); MetricsV0.DrainedCountIncrement(this.Endpoint.Id, messages.Length, priority); // Only move on to the next priority if the queue for the current // priority is empty. If we processed any messages, break out of // the inner loop to restart at the beginning of the priorities list // again. This is so we can catch and process any higher priority // messages that came in while we were sending the current batch haveMessagesRemaining = true; break; } } if (!haveMessagesRemaining) { // All the message queues have been drained, reset the hasMessagesInQueue flag. this.hasMessagesInQueue.Reset(); } } catch (Exception ex) { Events.SendMessagesError(this, ex); // Swallow exception and keep trying. } } } catch (Exception ex) { Events.SendMessagesPumpFailure(this, ex); } }