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