public bool CommitIfNecessary(bool localTx) { if (DeliveryTags.Count == 0) { return(false); } var isLocallyTransacted = localTx || (Transactional && TransactionSynchronizationManager.GetResource(ConnectionFactory) == null); try { var ackRequired = !AcknowledgeMode.IsAutoAck() && !AcknowledgeMode.IsManual(); if (ackRequired && (!Transactional || isLocallyTransacted)) { var deliveryTag = new List <ulong>(DeliveryTags)[DeliveryTags.Count - 1]; Channel.BasicAck(deliveryTag, true); } if (isLocallyTransacted) { // For manual acks we still need to commit RabbitUtils.CommitIfNecessary(Channel); } } finally { DeliveryTags.Clear(); } return(true); }
public Models.UrlRequest Post() { if (!Request.Form.ContainsKey("url")) { return(null); } var urls = Request.Form["url"]; var request = new Models.UrlRequest { Urls = urls, }; var requestString = JsonConvert.SerializeObject(request); var factory = RabbitUtils.GetRabbitConnection(); using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { channel.QueueDeclare(queue: "URL", durable: false, exclusive: false, autoDelete: false, arguments: null); var body = Encoding.UTF8.GetBytes(requestString); channel.BasicPublish(exchange: "", routingKey: "URL", basicProperties: null, body: body); Console.WriteLine("[URL] Sent {0}", requestString); } return(request); }
private SimpleConsumer Consume(string queue, Connection.IConnection connection) { R.IModel channel = null; SimpleConsumer consumer = null; try { channel = connection.CreateChannel(IsChannelTransacted); channel.BasicQos(0, (ushort)PrefetchCount, false); // TODO: Verify this consumer = new SimpleConsumer(this, connection, channel, queue); channel.QueueDeclarePassive(queue); consumer.ConsumerTag = channel.BasicConsume( queue, AcknowledgeMode.IsAutoAck(), ConsumerTagStrategy != null ? ConsumerTagStrategy.CreateConsumerTag(queue) : string.Empty, NoLocal, Exclusive, ConsumerArguments, consumer); } // catch (AmqpApplicationContextClosedException e) // { // throw new AmqpConnectException(e); // } catch (Exception e) { RabbitUtils.CloseChannel(channel, _logger); RabbitUtils.CloseConnection(connection, _logger); consumer = HandleConsumeException(queue, consumer, e); } return(consumer); }
private void CleanUpAfterInvoke(RabbitResourceHolder resourceHolder, R.IModel channelToUse, bool boundHere) { if (resourceHolder != null && boundHere) { // so the channel exposed (because exposeListenerChannel is false) will be closed resourceHolder.SynchronizedWithTransaction = false; } ConnectionFactoryUtils.ReleaseResources(resourceHolder); // NOSONAR - null check in method if (boundHere) { // unbind if we bound TransactionSynchronizationManager.UnbindResource(ConnectionFactory); if (!ExposeListenerChannel && IsChannelLocallyTransacted) { /* * commit the temporary channel we exposed; the consumer's channel * will be committed later. Note that when exposing a different channel * when there's no transaction manager, the exposed channel is committed * on each message, and not based on txSize. */ RabbitUtils.CommitIfNecessary(channelToUse, _logger); } } }
private void Rollback(ulong deliveryTag, Exception e) { if (_container.IsChannelTransacted) { RabbitUtils.RollbackIfNecessary(Model); } if (AckRequired || ContainerUtils.IsRejectManual(e)) { try { if (MessagesPerAck > 1) { lock (_lock) { if (PendingAcks > 0) { SendAck(DateTimeOffset.Now.ToUnixTimeMilliseconds()); } } } Model.BasicNack(deliveryTag, true, ContainerUtils.ShouldRequeue(_container.DefaultRequeueRejected, e, _logger)); } catch (IOException e1) { _logger?.LogError("Failed to nack message", e1); } } if (_container.IsChannelTransacted) { RabbitUtils.CommitIfNecessary(Model); } }
private void CancelConsumer(SimpleConsumer consumer) { try { _logger?.LogDebug("Canceling " + consumer); lock (consumer) { consumer.Canceled = true; if (MessagesPerAck > 1) { try { consumer.AckIfNecessary(0L); } catch (IOException e) { _logger?.LogError("Exception while sending delayed ack", e); } } } RabbitUtils.Cancel(consumer.Model, consumer.ConsumerTag, _logger); } finally { _consumers.Remove(consumer); ConsumerRemoved(consumer); } }
public void Stop() { if (AbortStarted == 0) { AbortStarted = DateTimeOffset.Now.ToUnixTimeMilliseconds(); } if (!Cancelled) { try { RabbitUtils.CloseMessageConsumer(Channel, GetConsumerTags(), Transactional); } catch (Exception e) { Logger?.LogDebug(e, "Error closing consumer: {consumer}", ToString()); } } Logger?.LogDebug("Closing Rabbit Channel : {channel}", Channel); RabbitUtils.SetPhysicalCloseRequired(Channel, true); ConnectionFactoryUtils.ReleaseResources(ResourceHolder); DeliveryTags.Clear(); _ = Consumers.TakeWhile((kvp) => Consumers.Count > 0); _ = Queue.TakeWhile((d) => Queue.Count > 0); }
public string Get(string id) { if (String.IsNullOrWhiteSpace(id)) { return("No ticket number provided"); } var factory = RabbitUtils.GetRabbitConnection(); using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { channel.QueueDeclare(queue: "JIRA", durable: false, exclusive: false, autoDelete: false, arguments: null); var body = Encoding.UTF8.GetBytes(id); channel.BasicPublish(exchange: "", routingKey: "JIRA", basicProperties: null, body: body); Console.WriteLine("[JIRA] Sent {0}", id); } return("Ticket accepted"); }
private void FinalizeConsumer() { RabbitUtils.SetPhysicalCloseRequired(Model, true); RabbitUtils.CloseChannel(Model); RabbitUtils.CloseConnection(_connection); _container._cancellationLock.Release(this); _container.ConsumerRemoved(this); }
/// <summary> /// Disposes this instance. /// </summary> public void Dispose() { if (this.target != null) { this.outer.ConnectionListener.OnClose(this.target); RabbitUtils.CloseConnection(this.target); } this.target = null; }
public void Destroy() { if (Target != null) { _factory.ConnectionListener.OnClose(Target); RabbitUtils.CloseConnection(Target); } Target = null; }
public void TestUninterruptibleListenerDMLC() { var cf = new CachingConnectionFactory("localhost"); var admin = new RabbitAdmin(cf); admin.DeclareQueue(new Config.Queue("test.shutdown")); var container = new DirectMessageListenerContainer(null, cf) { ShutdownTimeout = 500 }; container.SetQueueNames("test.shutdown"); var latch = new CountdownEvent(1); var testEnded = new CountdownEvent(1); var listener = new TestListener(latch, testEnded); container.MessageListener = listener; var connection = cf.CreateConnection() as ChannelCachingConnectionProxy; // var channels = TestUtils.getPropertyValue(connection, "target.delegate._channelManager._channelMap"); var field = typeof(RC.Framing.Impl.Connection) .GetField("m_sessionManager", BindingFlags.Instance | BindingFlags.NonPublic); Assert.NotNull(field); var channels = (SessionManager)field.GetValue(connection.Target.Connection); Assert.NotNull(channels); container.Start(); Assert.True(container._startedLatch.Wait(TimeSpan.FromSeconds(10))); try { var template = new RabbitTemplate(cf); template.Execute(c => { var properties = c.CreateBasicProperties(); var bytes = EncodingUtils.GetDefaultEncoding().GetBytes("foo"); c.BasicPublish(string.Empty, "test.shutdown", false, properties, bytes); RabbitUtils.SetPhysicalCloseRequired(c, false); }); Assert.True(latch.Wait(TimeSpan.FromSeconds(30))); Assert.Equal(2, channels.Count); } finally { container.Stop(); Assert.Equal(1, channels.Count); cf.Destroy(); testEnded.Signal(); admin.DeleteQueue("test.shutdown"); } }
protected override object DoReceive() { var connection = ConnectionFactory.CreateConnection(); var channel = connection.CreateChannel(Transacted); try { var resp = channel.BasicGet(QueueName, false); if (resp == null) { RabbitUtils.CloseChannel(channel); RabbitUtils.CloseConnection(connection); return(null); } var callback = AckCallbackFactory.CreateCallback(new RabbitAckInfo(connection, channel, Transacted, resp)); var envelope = new Envelope(resp.DeliveryTag, resp.Redelivered, resp.Exchange, resp.RoutingKey); var messageProperties = MessageHeaderConverter.ToMessageHeaders(resp.BasicProperties, envelope, EncodingUtils.Utf8); var accessor = RabbitHeaderAccessor.GetMutableAccessor(messageProperties); accessor.ConsumerQueue = this.QueueName; // Map<String, Object> headers = this.headerMapper.toHeadersFromRequest(messageProperties); var message = Message.Create <byte[]>(resp.Body, accessor.MessageHeaders); object payload; if (BatchingStrategy.CanDebatch(message.Headers)) { var payloads = new List <object>(); BatchingStrategy.DeBatch(message, fragment => payloads.Add(MessageConverter.FromMessage(fragment, null))); payload = payloads; } else { payload = MessageConverter.FromMessage(message, null); } var builder = MessageBuilderFactory.WithPayload(payload) .CopyHeaders(accessor.MessageHeaders) .SetHeader(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK, callback); if (RawMessageHeader) { builder.SetHeader(RabbitMessageHeaderErrorMessageStrategy.AMQP_RAW_MESSAGE, message); builder.SetHeader(IntegrationMessageHeaderAccessor.SOURCE_DATA, message); } return(builder); } catch (Exception e) { RabbitUtils.CloseChannel(channel); RabbitUtils.CloseConnection(connection); throw RabbitExceptionTranslator.ConvertRabbitAccessException(e); } }
/// <summary>Perform a rollback, handling rollback exceptions properly.</summary> /// <param name="ex">The thrown application exception.</param> public virtual void RollbackOnExceptionIfNecessary(Exception ex) { var ackRequired = !this.acknowledgeMode.IsAutoAck() && !this.acknowledgeMode.IsManual(); try { if (this.transactional) { Logger.Debug(m => m("Initiating transaction rollback on application exception"), ex); RabbitUtils.RollbackIfNecessary(this.channel); } if (ackRequired) { Logger.Debug(m => m("Rejecting message")); var shouldRequeue = this.defaultRequeueRejected; var t = ex; while (shouldRequeue && t != null) { if (t is AmqpRejectAndDontRequeueException) { shouldRequeue = false; } t = t.InnerException; } foreach (var deliveryTag in this.deliveryTags) { // With newer RabbitMQ brokers could use basicNack here... this.channel.BasicReject((ulong)deliveryTag, shouldRequeue); } if (this.transactional) { // Need to commit the reject (=nack) RabbitUtils.CommitIfNecessary(this.channel); } } } catch (Exception e) { Logger.Error(m => m("Application exception overriden by rollback exception"), ex); throw; } finally { this.deliveryTags.Clear(); } }
protected void BasicCancel(bool expected) { NormalCancel = expected; GetConsumerTags().ForEach(consumerTag => { if (Channel.IsOpen) { RabbitUtils.Cancel(Channel, consumerTag); } }); Cancel.Value = true; AbortStarted = DateTimeOffset.Now.ToUnixTimeMilliseconds(); }
/// <summary>Perform a commit or message acknowledgement, as appropriate</summary> /// <param name="locallyTransacted">if set to <c>true</c> [locally transacted].</param> /// <returns>True if committed, else false.</returns> public bool CommitIfNecessary(bool locallyTransacted) { if (this.deliveryTags == null || this.deliveryTags.Count < 1) { return(false); } try { var ackRequired = !this.acknowledgeMode.IsAutoAck() && !this.acknowledgeMode.IsManual(); if (ackRequired) { if (this.transactional && !locallyTransacted) { // Not locally transacted but it is transacted so it // could be synchronized with an external transaction foreach (var deliveryTag in this.deliveryTags) { ConnectionFactoryUtils.RegisterDeliveryTag(this.connectionFactory, this.channel, deliveryTag); } } else { if (this.deliveryTags != null && this.deliveryTags.Count > 0) { var copiedTags = new List <long>(this.deliveryTags); if (copiedTags.Count > 0) { var deliveryTag = copiedTags[copiedTags.Count - 1]; this.channel.BasicAck((ulong)deliveryTag, true); } } } } if (locallyTransacted) { // For manual acks we still need to commit RabbitUtils.CommitIfNecessary(this.channel); } } finally { this.deliveryTags.Clear(); } return(true); }
/// <summary>Sends the given response message to the given destination.</summary> /// <param name="channel">The channel to operate on.</param> /// <param name="replyTo">The replyto property to determine where to send a response.</param> /// <param name="message">The outgoing message about to be sent.</param> protected virtual void SendResponse(IModel channel, Address replyTo, Message message) { this.PostProcessChannel(channel, message); try { Logger.Debug(m => m("Publishing response to exchange = [{0}], routingKey = [{1}]", replyTo.ExchangeName, replyTo.RoutingKey)); channel.BasicPublish( replyTo.ExchangeName, replyTo.RoutingKey, this.mandatoryPublish, this.immediatePublish, this.messagePropertiesConverter.FromMessageProperties(channel, message.MessageProperties, this.encoding), message.Body); } catch (Exception ex) { throw RabbitUtils.ConvertRabbitAccessException(ex); } }
private List <string> ProcessStackTrace(Exception cause, string exceptionMessage) { var stackTraceAsString = cause.StackTrace; if (MaxStackTraceLength < 0) { var maxStackTraceLen = RabbitUtils.GetMaxFrame(ErrorTemplate.ConnectionFactory); if (maxStackTraceLen > 0) { maxStackTraceLen -= FrameMaxHeadroom; MaxStackTraceLength = maxStackTraceLen; } } return(TruncateIfNecessary(cause, exceptionMessage, stackTraceAsString)); }
private void CheckConsumers(long now) { List <SimpleConsumer> consumersToCancel; lock (_consumersMonitor) { consumersToCancel = _consumers .Where(consumer => { var open = consumer.Model.IsOpen && !consumer.AckFailed && !consumer.TargetChanged; if (open && MessagesPerAck > 1) { try { consumer.AckIfNecessary(now); } catch (IOException e) { _logger?.LogError("Exception while sending delayed ack", e); } } return(!open); }) .ToList(); } consumersToCancel .ForEach(consumer => { try { RabbitUtils.CloseMessageConsumer(consumer.Model, new List <string>() { consumer.ConsumerTag }, IsChannelTransacted, _logger); } catch (Exception e) { _logger?.LogDebug("Error closing consumer " + consumer, e); } _logger?.LogError("Consumer canceled - channel closed " + consumer); consumer.CancelConsumer("Consumer " + consumer + " channel closed"); }); }
static void Main(string[] args) { // Setup cancel key (Ctrl-C) Console.CancelKeyPress += (sender, eArgs) => { _quitEvent.Set(); eArgs.Cancel = true; }; // Initialize the JIRA listener Console.WriteLine("[RABBIT][JIRA] Listener starting"); var factory = RabbitUtils.GetRabbitConnection(); using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { channel.QueueDeclare(queue: "JIRA", durable: false, exclusive: false, autoDelete: false, arguments: null); var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body; var message = Encoding.UTF8.GetString(body); Console.WriteLine(String.Format("[RABBIT][JIRA] Received: {0}", message)); if (string.IsNullOrWhiteSpace(message)) { return; } // Send this ticket to the Orchestrator JiraAsync(message).GetAwaiter().GetResult(); }; channel.BasicConsume(queue: "JIRA", autoAck: true, consumer: consumer); Console.WriteLine("[RABBIT][JIRA] Listener started"); // Wait for the Ctrl-C to come through _quitEvent.WaitOne(); Console.WriteLine("[RABBIT][JIRA] Listener stopping..."); } }
public void Acknowledge(Status status) { // logger.trace("acknowledge(" + status + ") for " + this); try { var deliveryTag = AckInfo.Response.DeliveryTag; switch (status) { case Status.ACCEPT: AckInfo.Channel.BasicAck(deliveryTag, false); break; case Status.REJECT: AckInfo.Channel.BasicReject(deliveryTag, false); break; case Status.REQUEUE: AckInfo.Channel.BasicReject(deliveryTag, true); break; default: break; } if (AckInfo.Transacted) { AckInfo.Channel.TxCommit(); } } catch (Exception e) { throw RabbitExceptionTranslator.ConvertRabbitAccessException(e); } finally { RabbitUtils.CloseChannel(AckInfo.Channel); RabbitUtils.CloseConnection(AckInfo.Connection); IsAcknowledged = true; } }
protected virtual void CheckMismatchedQueues() { if (MismatchedQueuesFatal && AmqpAdmin != null) { try { AmqpAdmin.Initialize(); } catch (AmqpConnectException e) { _logger?.LogInformation("Broker not available; cannot check queue declarations", e); } catch (AmqpIOException e) { if (RabbitUtils.IsMismatchedQueueArgs(e)) { throw new FatalListenerStartupException("Mismatched queues", e); } else { _logger?.LogInformation("Failed to get connection during start(): ", e); } } } else { try { var connection = ConnectionFactory.CreateConnection(); if (connection != null) { connection.Close(); } } catch (Exception e) { _logger?.LogInformation("Broker not available; cannot force queue declarations during start: " + e.Message); } } }
private void HandleAck(ulong deliveryTag, bool channelLocallyTransacted) { /* * If we have a TX Manager, but no TX, act like we are locally transacted. */ var isLocallyTransacted = channelLocallyTransacted || (_container.IsChannelTransacted && TransactionSynchronizationManager.GetResource(ConnectionFactory) == null); try { if (AckRequired) { if (MessagesPerAck > 1) { lock (_lock) { LatestDeferredDeliveryTag = deliveryTag; PendingAcks++; AckIfNecessary(LastAck); } } else if (!_container.IsChannelTransacted || isLocallyTransacted) { Model.BasicAck(deliveryTag, false); } } if (isLocallyTransacted) { RabbitUtils.CommitIfNecessary(Model); } } catch (Exception e) { AckFailed = true; _logger?.LogError("Error acking", e); } }
/// <summary> /// Stop the channel. /// </summary> public void Stop() { this.cancelled.LazySet(true); if (this.consumer != null && this.consumer.Model != null && this.consumer.ConsumerTag != null && !this.cancelReceived.Value) { try { RabbitUtils.CloseMessageConsumer(this.consumer.Model, this.consumer.ConsumerTag, this.transactional); } catch (Exception ex) { Logger.Debug(m => m("Error closing consumer"), ex); } } Logger.Debug("Closing Rabbit Channel: " + this.channel); RabbitUtils.SetPhysicalCloseRequired(true); // This one never throws exceptions... RabbitUtils.CloseChannel(this.channel); this.deliveryTags.Clear(); this.consumer = null; }
protected virtual void RedeclareElementsIfNecessary() { lock (_lock) { var admin = AmqpAdmin; if (!IsLazyLoad && admin != null && AutoDeclare) { try { AttemptDeclarations(admin); } catch (Exception e) { if (RabbitUtils.IsMismatchedQueueArgs(e)) { throw new FatalListenerStartupException("Mismatched queues", e); } _logger?.LogError("Failed to check/redeclare auto-delete queue(s).", e); } } } }
public void RollbackOnExceptionIfNecessary(Exception ex) { bool ackRequired = !AcknowledgeMode.IsAutoAck() && (!AcknowledgeMode.IsManual() || ContainerUtils.IsRejectManual(ex)); try { if (Transactional) { Logger?.LogDebug(ex, "Initiating transaction rollback on application exception"); RabbitUtils.RollbackIfNecessary(Channel); } if (ackRequired) { if (DeliveryTags.Count > 0) { ulong deliveryTag = DeliveryTags.Max(); Channel.BasicNack(deliveryTag, true, ContainerUtils.ShouldRequeue(DefaultRequeueRejected, ex, Logger)); } if (Transactional) { // Need to commit the reject (=nack) RabbitUtils.CommitIfNecessary(Channel); } } } catch (Exception e) { Logger?.LogError(ex, "Application exception overridden by rollback exception"); throw RabbitExceptionTranslator.ConvertRabbitAccessException(e); // NOSONAR stack trace loss } finally { DeliveryTags.Clear(); } }
public override void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, RC.IBasicProperties properties, byte[] body) { Logger?.LogDebug("Storing delivery for consumer tag: {tag} with deliveryTag: {deliveryTag} for consumer: {consumer}", ConsumerTag, deliveryTag, ToString()); try { var delivery = new Delivery(consumerTag, new Envelope(deliveryTag, redelivered, exchange, routingKey), properties, body, QueueName); if (Consumer.AbortStarted > 0) { if (!Consumer.Queue.TryAdd(delivery, Consumer.ShutdownTimeout)) { RabbitUtils.SetPhysicalCloseRequired(Model, true); _ = Consumer.Queue.TakeWhile((d) => Consumer.Queue.Count > 0); if (!Canceled) { RabbitUtils.Cancel(Model, consumerTag); } try { Model.Close(); } catch (Exception) { // Noop } } } else { Consumer.Queue.TryAdd(delivery); } } catch (Exception e) { Logger?.LogWarning(e, "Unexpected exception during delivery"); } }
/// <summary>The start.</summary> public void Start() { Logger.Debug(m => m("Starting consumer {0}", this)); this.channel = ConnectionFactoryUtils.GetTransactionalResourceHolder(this.connectionFactory, this.transactional).Channel; this.consumer = new InternalConsumer(this.channel, this); this.deliveryTags.Clear(); this.activeObjectCounter.Add(this); var passiveDeclareTries = 3; // mirrored queue might be being moved while (passiveDeclareTries > 0) { passiveDeclareTries--; try { if (!this.acknowledgeMode.IsAutoAck()) { // Set basicQos before calling basicConsume (otherwise if we are not acking the broker // will send blocks of 100 messages) // The Java client includes a convenience method BasicQos(ushort prefetchCount), which sets 0 as the prefetchSize and false as global this.channel.BasicQos(0, (ushort)this.prefetchCount, false); } foreach (var t in this.queues) { this.channel.QueueDeclarePassive(t); } passiveDeclareTries = 0; } catch (Exception e) { if (passiveDeclareTries > 0 && this.channel.IsOpen) { Logger.Warn(m => m("Reconnect failed; retries left=" + (passiveDeclareTries - 1)), e); try { Thread.Sleep(5000); } catch (ThreadInterruptedException e1) { Thread.CurrentThread.Interrupt(); } } else { this.activeObjectCounter.Release(this); throw new FatalListenerStartupException("Cannot prepare queue for listener. Either the queue doesn't exist or the broker will not allow us to use it.", e); } } } try { foreach (var t in this.queues) { this.channel.BasicConsume(t, this.acknowledgeMode.IsAutoAck(), this.consumer); Logger.Debug(m => m("Started on queue '{0}': {1}", t, this)); } } catch (Exception e) { throw RabbitUtils.ConvertRabbitAccessException(e); } }
/// <summary>Converts a rabbit access exception.</summary> /// <param name="ex">The ex.</param> /// <returns>The system exception.</returns> protected Exception ConvertRabbitAccessException(Exception ex) { return(RabbitUtils.ConvertRabbitAccessException(ex)); }
public async Task TestDeclareDelayedExchange() { provider = services.BuildServiceProvider(); var rabbitAdmin = provider.GetRabbitAdmin(); var exchange = new DirectExchange("test.delayed.exchange") { IsDelayed = true }; var queue = new Queue(Guid.NewGuid().ToString(), true, false, false); var exchangeName = exchange.ExchangeName; var binding = new Binding("baz", queue.QueueName, DestinationType.QUEUE, exchangeName, queue.QueueName, null); try { rabbitAdmin.DeclareExchange(exchange); } catch (RabbitIOException e) { if (RabbitUtils.IsExchangeDeclarationFailure(e)) { var inner = e.InnerException; if (inner.Message.Contains("exchange type 'x-delayed-message'")) { return; // Broker doesn't support? } } throw; } rabbitAdmin.DeclareQueue(queue); rabbitAdmin.DeclareBinding(binding); var cf = provider.GetRabbitConnectionFactory(); var context = provider.GetApplicationContext(); var pp = new TestPostProcessor(); var template = new RabbitTemplate(cf) { ReceiveTimeout = 10000 }; template.ConvertAndSend(exchangeName, queue.QueueName, "foo", pp); var headers = RabbitHeaderAccessor.GetMutableAccessor(new MessageHeaders()); headers.Delay = 500; var send = MessageBuilder.WithPayload(Encoding.UTF8.GetBytes("foo")).SetHeaders(headers).Build(); template.Send(exchangeName, queue.QueueName, send); var t1 = DateTimeOffset.Now.ToUnixTimeMilliseconds(); var received = template.Receive(queue.QueueName); Assert.NotNull(received); var delay = received.Headers.ReceivedDelay(); Assert.NotNull(delay); Assert.Equal(500, delay.Value); received = template.Receive(queue.QueueName); Assert.NotNull(received); delay = received.Headers.ReceivedDelay(); Assert.NotNull(delay); Assert.Equal(1000, delay.Value); var t2 = DateTimeOffset.Now.ToUnixTimeMilliseconds(); var dif = t2 - t1; Assert.InRange(dif, 950, 1250); var config = await GetExchange(exchangeName); Assert.Equal("direct", config.GetValue <string>("x-delayed-type")); Assert.Equal("x-delayed-message", config.GetValue <string>("type")); }