示例#1
0
 public MongoBasicPropertiesDocument(IBasicProperties props)
 {
     ContentEncoding = props.ContentEncoding;
     ContentType     = props.ContentType;
     MessageHeader   = new MessageHeader(props.Headers, Encoding.UTF8);
     XDeathHeaders   = new RabbitMqXDeathHeaders(props.Headers, Encoding.UTF8);
     UnixTimestamp   = props.Timestamp.UnixTime;
 }
示例#2
0
        public void TestCopyHeaders()
        {
            IEnumerable <string> xDeathHeaderNames = typeof(RabbitMqXDeathHeaders)
                                                     .GetFields(BindingFlags.Public | BindingFlags.Static)
                                                     .Where(fi => (fi.FieldType.IsAssignableFrom(typeof(string))))
                                                     .Select(x => (string)x.GetValue(null));

            Dictionary <string, object> source = xDeathHeaderNames.ToDictionary <string, string, object>(item => item, item => "test");

            source.Add("other", "garbage data");
            var target = new Dictionary <string, object>();

            Assert.DoesNotThrow(() => RabbitMqXDeathHeaders.CopyHeaders(source, target));

            source.Remove("other");
            Assert.True(source.Count == target.Count && !source.Except(target).Any());
        }
示例#3
0
        public void TestCaptureOfXDeathHeaders()
        {
            var testMessage = new AccessionDirectoryMessage
            {
                NationalPACSAccessionNumber = "1234",
                DirectoryPath = @"C:\temp"
            };

            _testHelper.TestProducer.SendMessage(testMessage, null, DeadLetterTestHelper.TestRoutingKey);

            new TestTimelineAwaiter().Await(() => _testHelper.MessageRejectorConsumer.NackCount == 1);

            BasicGetResult getResult = _testHelper.TestModel.BasicGet(DeadLetterTestHelper.TestDlQueueName, true);

            var xHeaders = new RabbitMqXDeathHeaders(getResult.BasicProperties.Headers, Encoding.UTF8);

            // Can't really get the expected time, just have to copy from the result
            long expectedTime = xHeaders.XDeaths[0].Time;

            var expectedHeaders = new RabbitMqXDeathHeaders
            {
                XDeaths = new List <RabbitMqXDeath>
                {
                    new RabbitMqXDeath
                    {
                        Count       = 1,
                        Exchange    = DeadLetterTestHelper.RejectExchangeName,
                        Queue       = DeadLetterTestHelper.RejectQueueName,
                        Reason      = "rejected",
                        RoutingKeys = new List <string>
                        {
                            DeadLetterTestHelper.TestRoutingKey
                        },
                        Time = expectedTime
                    }
                },
                XFirstDeathExchange = DeadLetterTestHelper.RejectExchangeName,
                XFirstDeathQueue    = DeadLetterTestHelper.RejectQueueName,
                XFirstDeathReason   = "rejected",
            };

            Assert.AreEqual(expectedHeaders, xHeaders);
        }
示例#4
0
        private void RepublishMessage(BasicDeliverEventArgs deliverArgs)
        {
            var exchangeForRepublish = (string)deliverArgs.BasicProperties.Headers[RabbitMqXDeathHeaders.XFirstDeathExchangeKey];

            try
            {
                _model.ExchangeDeclarePassive(exchangeForRepublish);
            }
            catch (OperationInterruptedException e)
            {
                // If an exchange doesn't exist, then we are forced to Fatal the host
                throw new ApplicationException("Exchange for republishing did not exist (\"" + exchangeForRepublish + "\")", e);
            }

            _props.Timestamp = new AmqpTimestamp(MessageHeader.UnixTimeNow());

            // Clear the existing headers so we can update them and re-add
            ClearMessageHeaders(_props.Headers);

            // Update the new message props with the existing data from the deliverArgs
            var existingHeader = new MessageHeader(deliverArgs.BasicProperties.Headers);

            new MessageHeader(existingHeader).Populate(_props.Headers);
            RabbitMqXDeathHeaders.CopyHeaders(deliverArgs.BasicProperties.Headers, _props.Headers);

            _model.BasicPublish(exchangeForRepublish, deliverArgs.RoutingKey, true, _props, deliverArgs.Body);

            try
            {
                _model.WaitForConfirmsOrDie(_confirmTimeout);
            }
            catch (Exception e)
            {
                // If we can't republish a certain message, send it to graveyard
                _logger.Error(e, "WaitForConfirmsOrDie Died");
                _deadLetterStore.SendToGraveyard(existingHeader.MessageGuid, "Couldn't republish", e);
                return;
            }

            _deadLetterStore.NotifyMessageRepublished(existingHeader.MessageGuid);
            ++TotalRepublished;
        }
示例#5
0
        public override void ProcessMessage(BasicDeliverEventArgs deliverArgs)
        {
            Encoding      enc = Encoding.UTF8;
            MessageHeader header;

            try
            {
                if (deliverArgs.BasicProperties.ContentEncoding != null)
                {
                    enc = Encoding.GetEncoding(deliverArgs.BasicProperties.ContentEncoding);
                }

                header = new MessageHeader(deliverArgs.BasicProperties.Headers, enc);
                header.Log(Logger, NLog.LogLevel.Trace, "Received");
            }
            catch (Exception e)
            {
                Logger.Error("Message header content was null, or could not be parsed into a MessageHeader object: " + e);

                DiscardSingleMessage(deliverArgs.DeliveryTag);

                return;
            }

            //Bug: RabbitMQ lib doesn't properly handle the ReplyTo address being null, causing the mapping to MongoDB types to throw an exception
            if (deliverArgs.BasicProperties.ReplyTo == null)
            {
                deliverArgs.BasicProperties.ReplyTo = "";
            }

            RabbitMqXDeathHeaders deathHeaders;

            try
            {
                deathHeaders = new RabbitMqXDeathHeaders(deliverArgs.BasicProperties.Headers, Encoding.UTF8);
            }
            catch (ArgumentException)
            {
                _deadLetterStore.SendToGraveyard(deliverArgs, header, "Message contained invalid x-death entries");

                Ack(header, deliverArgs.DeliveryTag);
                return;
            }

            if (deathHeaders.XDeaths[0].Count - 1 >= _maxRetryLimit)
            {
                _deadLetterStore.SendToGraveyard(deliverArgs, header, "MaxRetryCount exceeded");

                Ack(header, deliverArgs.DeliveryTag);
                return;
            }

            try
            {
                _deadLetterStore.PersistMessageToStore(deliverArgs, header, _defaultRetryAfter);
            }
            catch (Exception e)
            {
                _deadLetterStore.SendToGraveyard(deliverArgs, header, "Exception when storing message", e);
            }

            Ack(header, deliverArgs.DeliveryTag);
        }
示例#6
0
        public void TestBasicOperation()
        {
            Assert.True(_deadLetterCollection.CountDocuments(FilterDefinition <MongoDeadLetterDocument> .Empty) == 0);
            Assert.True(_deadLetterGraveyard.CountDocuments(FilterDefinition <MongoDeadLetterGraveyardDocument> .Empty) == 0);

            // Setup a test message and send it, then wait for it to be rejected
            var testMessage = new AccessionDirectoryMessage
            {
                NationalPACSAccessionNumber = "1234",
                DirectoryPath = TestContext.CurrentContext.TestDirectory
            };

            _testHelper.TestProducer.SendMessage(testMessage, null, DeadLetterTestHelper.TestRoutingKey);
            new TestTimelineAwaiter().Await(() => _testHelper.MessageRejectorConsumer.NackCount == 1);

            IMessageHeader        originalHeader = _testHelper.MessageRejectorConsumer.LastHeader;
            BasicDeliverEventArgs originalArgs   = _testHelper.MessageRejectorConsumer.LastArgs;

            Assert.NotNull(originalHeader);
            Assert.NotNull(originalArgs);

            // Set so the next message is accepted
            _testHelper.MessageRejectorConsumer.AcceptNext = true;

            // Check 1 message on the DLQ
            Assert.AreEqual(1, _testHelper.TestModel.MessageCount(DeadLetterTestHelper.TestDlQueueName));

            // Start the host and check message has been read from DLQ into store
            var host = new DeadLetterReprocessorHost(_testHelper.GlobalOptions, _cliOptions);

            host.Start();

            Assert.True(_deadLetterCollection.CountDocuments(FilterDefinition <MongoDeadLetterDocument> .Empty) == 1);
            Assert.True(_deadLetterGraveyard.CountDocuments(FilterDefinition <MongoDeadLetterGraveyardDocument> .Empty) == 0);
            Assert.AreEqual(0, _testHelper.TestModel.MessageCount(DeadLetterTestHelper.TestDlQueueName));

            // Now run the host again with the FlushMessages option set
            _cliOptions.FlushMessages = true;
            host = new DeadLetterReprocessorHost(_testHelper.GlobalOptions, _cliOptions);
            host.Start();

            // Check the message has been sent back to the exchange and received by the consumer
            Assert.True(_deadLetterCollection.CountDocuments(FilterDefinition <MongoDeadLetterDocument> .Empty) == 0);
            Assert.True(_deadLetterGraveyard.CountDocuments(FilterDefinition <MongoDeadLetterGraveyardDocument> .Empty) == 0);
            new TestTimelineAwaiter().Await(() => _testHelper.MessageRejectorConsumer.AckCount == 1);

            IMessageHeader        reprocessedHeader = _testHelper.MessageRejectorConsumer.LastHeader;
            BasicDeliverEventArgs reprocessedArgs   = _testHelper.MessageRejectorConsumer.LastArgs;

            Assert.NotNull(reprocessedHeader);
            Assert.NotNull(reprocessedArgs);

            // Check the received message matches the original (where expected)
            Assert.AreNotEqual(originalHeader.MessageGuid, reprocessedHeader.MessageGuid);
            Assert.AreEqual(originalHeader.ProducerExecutableName, reprocessedHeader.ProducerExecutableName);
            Assert.AreEqual(originalHeader.ProducerProcessID, reprocessedHeader.ProducerProcessID);
            Assert.AreEqual(originalHeader.OriginalPublishTimestamp, reprocessedHeader.OriginalPublishTimestamp);
            Assert.True(reprocessedHeader.IsDescendantOf(originalHeader));

            // Check the xDeathHeaders
            var reprocessedXDeathHeaders = new RabbitMqXDeathHeaders(reprocessedArgs.BasicProperties.Headers, Encoding.UTF8);

            // Can't really get the expected time, just have to copy from the result
            long expectedTime = reprocessedXDeathHeaders.XDeaths[0].Time;

            var expectedXDeathHeaders = new RabbitMqXDeathHeaders
            {
                XDeaths = new List <RabbitMqXDeath>
                {
                    new RabbitMqXDeath
                    {
                        Count       = 1,
                        Exchange    = DeadLetterTestHelper.RejectExchangeName,
                        Queue       = DeadLetterTestHelper.RejectQueueName,
                        Reason      = "rejected",
                        RoutingKeys = new List <string>
                        {
                            DeadLetterTestHelper.TestRoutingKey
                        },
                        Time = expectedTime
                    }
                },
                XFirstDeathExchange = DeadLetterTestHelper.RejectExchangeName,
                XFirstDeathQueue    = DeadLetterTestHelper.RejectQueueName,
                XFirstDeathReason   = "rejected",
            };

            Assert.AreEqual(expectedXDeathHeaders, reprocessedXDeathHeaders);
        }