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); }
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); }