public void When_requeueing_a_message() { _producer.Send(_message); var channel = _channelFactory.CreateChannel(_subscription); var message = channel.Receive(2000); channel.Requeue(message, 100); var requeuedMessage = channel.Receive(1000); //clear the queue channel.Acknowledge(requeuedMessage); requeuedMessage.Body.Value.Should().Be(message.Body.Value); }
public void When_requeueing_a_message() { ((IAmAMessageProducerSync)_producerRegistry.LookupBy(_topic)).Send(_message); var channel = _channelFactory.CreateChannel(_subscription); var message = channel.Receive(2000); channel.Requeue(message, 100); var requeuedMessage = channel.Receive(1000); //clear the queue channel.Acknowledge(requeuedMessage); requeuedMessage.Body.Value.Should().Be(message.Body.Value); }
/// <summary> /// Uses the Request-Reply messaging approach to send a message to another server and block awaiting a reply. /// The message is placed into a message queue but not into the outbox. /// An ephemeral reply queue is created, and its name used to set the reply address for the response. We produce /// a queue per exchange, to simplify correlating send and receive. /// The response is directed to a registered handler. /// Because the operation blocks, there is a mandatory timeout /// </summary> /// <param name="request">What message do we want a reply to</param> /// <param name="timeOutInMilliseconds">The call blocks, so we must time out</param> /// <exception cref="NotImplementedException"></exception> public TResponse Call <T, TResponse>(T request, int timeOutInMilliseconds) where T : class, ICall where TResponse : class, IResponse { if (timeOutInMilliseconds <= 0) { throw new InvalidOperationException("Timeout to a call method must have a duration greater than zero"); } var outMessageMapper = _mapperRegistry.Get <T>(); if (outMessageMapper == null) { throw new ArgumentOutOfRangeException( $"No message mapper registered for messages of type: {typeof(T)}"); } var inMessageMapper = _mapperRegistry.Get <TResponse>(); if (inMessageMapper == null) { throw new ArgumentOutOfRangeException( $"No message mapper registered for messages of type: {typeof(T)}"); } //create a reply queue via creating a consumer - we use random identifiers as we will destroy var channelName = Guid.NewGuid(); var routingKey = channelName.ToString(); using (var responseChannel = _responseChannelFactory.CreateChannel( new Connection( typeof(TResponse), channelName: new ChannelName(channelName.ToString()), routingKey: new RoutingKey(routingKey)))) { _logger.Value.InfoFormat("Create reply queue for topic {0}", routingKey); request.ReplyAddress.Topic = routingKey; request.ReplyAddress.CorrelationId = channelName; //we do this to create the channel on the broker, or we won't have anything to send to; we //retry in case the connection is poor. An alternative would be to extract the code from //the channel to create the connection, but this does not do much on a new queue Retry(() => responseChannel.Purge()); var outMessage = outMessageMapper.MapToMessage(request); //We don't store the message, if we continue to fail further retry is left to the sender _logger.Value.DebugFormat("Sending request with routingkey {0}", routingKey); Retry(() => _messageProducer.Send(outMessage)); Message responseMessage = null; //now we block on the receiver to try and get the message, until timeout. _logger.Value.DebugFormat("Awaiting response on {0}", routingKey); Retry(() => responseMessage = responseChannel.Receive(timeOutInMilliseconds)); TResponse response = default(TResponse); if (responseMessage.Header.MessageType != MessageType.MT_NONE) { _logger.Value.DebugFormat("Reply received from {0}", routingKey); //map to request is map to a response, but it is a request from consumer point of view. Confusing, but... response = inMessageMapper.MapToRequest(responseMessage); Send(response); } _logger.Value.InfoFormat("Deleting queue for routingkey: {0}", routingKey); return(response); } //clean up everything at this point, whatever happens }