public void WireUpContextFeatures <TMessageContext>(TMessageContext context, IRawConsumer consumer, BasicDeliverEventArgs args) where TMessageContext : IMessageContext { if (context == null) { return; } var advancedCtx = context as IAdvancedMessageContext; if (advancedCtx == null) { return; } advancedCtx.Nack = () => { consumer.AcknowledgedTags.Add(args.DeliveryTag); consumer.Model.BasicNack(args.DeliveryTag, false, true); }; advancedCtx.RetryLater = timespan => { var dlxName = _conventions.DeadLetterExchangeNamingConvention(); var dlQueueName = _conventions.RetryQueueNamingConvention(); var channel = _channelFactory.CreateChannel(); channel.ExchangeDeclare(dlxName, ExchangeType.Direct); channel.QueueDeclare(dlQueueName, false, false, true, new Dictionary <string, object> { { QueueArgument.DeadLetterExchange, args.Exchange }, { QueueArgument.MessageTtl, Convert.ToInt32(timespan.TotalMilliseconds) } }); channel.QueueBind(dlQueueName, dlxName, args.RoutingKey, null); UpdateHeaders(args.BasicProperties); channel.BasicPublish(dlxName, args.RoutingKey, args.BasicProperties, args.Body); Timer disposeChannel = null; disposeChannel = new Timer(state => { channel.QueueDelete(dlQueueName); //TODO: investigate why auto-delete doesn't work? channel.Dispose(); disposeChannel?.Dispose(); }, null, timespan.Add(TimeSpan.FromMilliseconds(20)), new TimeSpan(-1)); }; advancedCtx.RetryInfo = GetRetryInformatino(args.BasicProperties); }