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);
            }
        }
Example #2
0
        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);
            }
        }