private async Task <bool> GetNextGroupIfNeeded(IRabbitMqConsumer consumer)
        {
            // Repeat until we run out of messages, or we have set _currentGroup to a non-empty collection.
            while (_currentGroup.Count == 0)
            {
                var item = await consumer.ReceiveAsync();

                if (item == null)
                {
                    return(false);
                }

                List <IBatchContainer> batches;
                try
                {
                    batches     = _dataAdapter.FromQueueMessage(item, ++_sequenceId).ToList();
                    _sequenceId = batches.LastOrDefault()?.SequenceToken?.SequenceNumber ?? _sequenceId;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "GetQueueMessagesAsync: failed to deserialize the message! The message will be thrown away.");
                    await consumer.NackAsync(item.Channel, item.DeliveryTag, requeue : false);

                    continue;
                }

                if (_rmqOptions.RequireMatchingQueue)
                {
                    // Filter out any decoded batches whose streams that do not belong to the queue. (Can happen with custom data adapters,
                    // and unusual topologies. If it does we don't want to try to deliver those because those messages should also appear
                    // in the correct queue, and thus would get needlessly double delivered.)

                    // This is optional because for some topologies (like those using x-consistent-hash or x-modulus-hash), orleans will
                    // not know which queue to expect a message on, and therefore cannot filter, and must rely on the topology
                    // ensuring no needless duplicates.

                    batches = batches.Where(b => _mapper.GetQueueForStream(b.StreamGuid, b.StreamNamespace).Equals(_queueId)).ToList();
                }

                if (batches.Count == 0)
                {
                    // If a RabbitMQ message maps to zero Orleans messages, then we can acknowledge it immediately.
                    await consumer.AckAsync(item.Channel, item.DeliveryTag, multiple : false);
                }
                else
                {
                    foreach (var batch in batches)
                    {
                        _pending.Add(new PendingDelivery(batch.SequenceToken, item.DeliveryTag, item.Channel, item.RequeueOnFailure));
                    }
                }

                _currentGroup = new Queue <IBatchContainer>(batches);
            }

            return(true);
        }
Example #2
0
        private async Task <bool> GetNextGroupIfNeeded(IRabbitMqConsumer consumer)
        {
            // Repeat until we run out of messages, or we have set _currentGroup to a non-empty collection.
            while (_currentGroup.Count == 0)
            {
                var item = await consumer.ReceiveAsync();

                if (item == null)
                {
                    return(false);
                }

                IEnumerable <IBatchContainer> batches;
                try
                {
                    batches = _dataAdapter.FromQueueMessage(item, _sequenceId++);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "GetQueueMessagesAsync: failed to deserialize the message! The message will be thrown away.");
                    await consumer.NackAsync(item.Channel, item.DeliveryTag, requeue : false);

                    continue;
                }

                // Filter out any decoded batches whose streams that do not belong to the queue. (Can happen with custom data adapters,
                // and unusual typologies. If it does we don't want to try to deliver those because those messages should also appear
                // in the correct queue, and thus would get needlessly double delivered.)
                var filteredBatches = batches.Where(b => _mapper.GetQueueForStream(b.StreamGuid, b.StreamNamespace) == _queueId).ToList();

                if (filteredBatches.Count == 0)
                {
                    // If a RabbitMQ message maps to zero Orleans messages, then we can acknowledge it immediately.
                    await consumer.AckAsync(item.Channel, item.DeliveryTag, multiple : false);
                }
                else
                {
                    foreach (var batch in filteredBatches)
                    {
                        pending.Add(new PendingDelivery(batch.SequenceToken, item.DeliveryTag, item.Channel, item.RequeueOnFailure));
                    }
                }

                _currentGroup = new Queue <IBatchContainer>(filteredBatches);
            }

            return(true);
        }