void EnsureConsumerInitialized()
        {
            // if the consumer is null at this point, we see if we can initialize it...
            if (_consumer == null)
            {
                lock (_consumerInitializationLock)
                {
                    // if there is a consumer instance at this point, someone else went and initialized it...
                    if (_consumer == null)
                    {
                        try
                        {
                            _consumer = InitializeConsumer();
                        }
                        catch (OperationInterruptedException objectInterruptedException) when(objectInterruptedException.Message.Contains("code=404, text=\"NOT_FOUND - no queue"))
                        {
                            _log.Warn("Queue not found - attempting to recreate queue and restore subscriptions.");
                            ReconnectQueue();
                            _consumer = InitializeConsumer();
                        }
                        catch (Exception exception)
                        {
                            _log.Warn("Could not initialize consumer: {0} - waiting 2 seconds", exception);

                            Thread.Sleep(2000);
                        }
                    }
                }
            }
        }
        void ClearConsumer()
        {
            var currentConsumer = _consumer;

            _consumer = null;

            if (currentConsumer == null)
            {
                return;
            }

            try
            {
                currentConsumer.Model.Dispose();
            }
            catch { }
        }
        /// <summary>
        /// Creates the consumer.
        /// </summary>
        CustomQueueingConsumer InitializeConsumer()
        {
            IConnection connection = null;
            IModel      model      = null;

            try
            {
                // receive must be done with separate model
                connection = _connectionManager.GetConnection();

                model = connection.CreateModel();
                model.BasicQos(0, _maxMessagesToPrefetch, false);

                var consumer = new CustomQueueingConsumer(model);

                model.BasicConsume(Address, false, consumer);

                _log.Info("Successfully initialized consumer for {queueName}", Address);

                return(consumer);
            }
            catch (OperationInterruptedException objectInterruptedException) when(objectInterruptedException.Message.Contains("code=404, text=\"NOT_FOUND - no queue"))
            {
                _log.Warn("Queue not found - attempting to recreate queue and restore subscriptions.");
                ReconnectQueue();
                return(null);
            }
            catch (Exception)
            {
                try
                {
                    model?.Dispose();
                }
                catch { }

                try
                {
                    connection?.Dispose();
                }
                catch { }

                throw;
            }
        }
        /// <summary>
        /// Creates the consumer.
        /// </summary>
        CustomQueueingConsumer InitializeConsumer()
        {
            IConnection connection = null;
            IModel      model      = null;

            try
            {
                // receive must be done with separate model
                connection = _connectionManager.GetConnection();
                model      = connection.CreateModel();
                model.BasicQos(0, _maxMessagesToPrefetch, false);
                var consumer = new CustomQueueingConsumer(model);

                model.BasicConsume(Address, false, consumer);

                _log.Info("Successfully initialized consumer for {0}", Address);

                return(consumer);
            }
            catch (Exception)
            {
                try
                {
                    model?.Dispose();
                }
                catch { }

                try
                {
                    connection?.Dispose();
                }
                catch { }

                throw;
            }
        }
        void EnsureConsumerInitialized()
        {
            // if the consumer is null at this point, we see if we can initialize it...
            if (_consumer == null)
            {
                lock (_consumerInitializationLock)
                {
                    // if there is a consumer instance at this point, someone else went and initialized it...
                    if (_consumer == null)
                    {
                        try
                        {
                            _consumer = InitializeConsumer();
                        }
                        catch (Exception exception)
                        {
                            _log.Warn("Could not initialize consumer: {0} - waiting 2 seconds", exception);

                            Thread.Sleep(2000);
                        }
                    }
                }
            }
        }
        /// <inheritdoc />
        public async Task <TransportMessage> Receive(ITransactionContext context, CancellationToken cancellationToken)
        {
            if (Address == null)
            {
                throw new InvalidOperationException("This RabbitMQ transport does not have an input queue - therefore, it is not possible to reveive anything");
            }

            try
            {
                EnsureConsumerInitialized();

                var consumer = _consumer;

                // initialization must have failed
                if (consumer == null)
                {
                    return(null);
                }

                var model = consumer.Model;

                if (!model.IsOpen)
                {
                    // something is wrong - we would not be able to ACK messages - force re-initialization to happen
                    _consumer = null;

                    // try to get rid of the consumer we have here
                    try
                    {
                        model.Dispose();
                    }
                    catch { }
                }

                BasicDeliverEventArgs result;
                if (!consumer.Queue.Dequeue(TwoSeconds, out result))
                {
                    return(null);
                }

                var deliveryTag = result.DeliveryTag;

                context.OnCommitted(async() =>
                {
                    model.BasicAck(deliveryTag, false);
                });

                context.OnAborted(() =>
                {
                    // we might not be able to do this, but it doesn't matter that much if it succeeds
                    try
                    {
                        model.BasicNack(deliveryTag, false, true);
                    }
                    catch { }
                });

                return(CreateTransportMessage(result.BasicProperties, result.Body));
            }
            catch (EndOfStreamException exception)
            {
                ClearConsumer();

                throw new RebusApplicationException(exception,
                                                    "Queue throw EndOfStreamException(meaning it was canceled by rabbitmq)");
            }
            catch (Exception exception)
            {
                ClearConsumer();

                Thread.Sleep(1000);

                throw new RebusApplicationException(exception,
                                                    $"unexpected exception thrown while trying to dequeue a message from rabbitmq, queue address: {Address}");
            }
        }