/// <summary>Restart the consumer.</summary>
        /// <param name="consumer">The consumer.</param>
        internal void Restart(BlockingQueueConsumer consumer)
        {
            lock (this.consumersMonitor)
            {
                if (this.consumers != null)
                {
                    try
                    {
                        // Need to recycle the channel in this consumer
                        consumer.Stop();

                        // Ensure consumer counts are correct (another is not going
                        // to start because of the exception, but
                        // we haven't counted down yet)
                        this.cancellationLock.Release(consumer);
                        this.consumers.Remove(consumer);
                        consumer = this.CreateBlockingQueueConsumer();
                        this.consumers.Add(consumer);
                    }
                    catch (Exception e)
                    {
                        Logger.Warn(m => m("Consumer failed irretrievably on restart. {0}: {1}", e.Source, e.Message));

                        // Re-throw and have it logged properly by the caller.
                        throw;
                    }

                    var processor    = new AsyncMessageProcessingConsumer(consumer, this);
                    var taskExecutor = new Task(processor.Run);
                    taskExecutor.Start();
                }
            }
        }
        /// <summary>Receive and execute.</summary>
        /// <param name="consumer">The consumer.</param>
        /// <returns>True if a message was received.</returns>
        internal bool ReceiveAndExecute(BlockingQueueConsumer consumer)
        {
            if (this.transactionManager != null)
            {
                try
                {
                    var transactionTemplate = new TransactionTemplate(this.transactionManager);
                    transactionTemplate.PropagationBehavior       = this.transactionAttribute.PropagationBehavior;
                    transactionTemplate.TransactionIsolationLevel = IsolationLevel.Unspecified; // TODO: revert to transactionAttribute once we take dependency on SPRNET 2.0
                    transactionTemplate.TransactionTimeout        = this.transactionAttribute.TransactionTimeout;
                    transactionTemplate.ReadOnly = this.transactionAttribute.ReadOnly;
                    transactionTemplate.Name     = this.transactionAttribute.Name;

                    return((bool)transactionTemplate.Execute(
                               status =>
                    {
                        ConnectionFactoryUtils.BindResourceToTransaction(new RabbitResourceHolder(consumer.Channel, false), this.ConnectionFactory, true);
                        return this.DoReceiveAndExecute(consumer);
                    }));
                }
                catch (Exception ex)
                {
                    Logger.Error(m => m("Error receiving and executing."), ex);
                    throw;
                }
            }

            return(this.DoReceiveAndExecute(consumer));
        }
        /// <summary>Perform receive and execute actions.</summary>
        /// <param name="consumer">The consumer.</param>
        /// <returns>True if a message was received.</returns>
        private bool DoReceiveAndExecute(BlockingQueueConsumer consumer)
        {
            var channel = consumer.Channel;

            for (var i = 0; i < this.txSize; i++)
            {
                Logger.Trace(m => m("Waiting for message from consumer."));
                var message = consumer.NextMessage(this.receiveTimeout);
                if (message == null)
                {
                    break;
                }

                try
                {
                    this.ExecuteListener(channel, message);
                }
                catch (ImmediateAcknowledgeAmqpException e)
                {
                    Logger.Trace(m => m("DoReceiveAndExecute => "), e);
                    break;
                }
                catch (Exception ex)
                {
                    consumer.RollbackOnExceptionIfNecessary(ex);
                    throw;
                }
            }

            return(consumer.CommitIfNecessary(this.IsChannelLocallyTransacted(channel)));
        }
        public void TestTransactionalLowLevel()
        {
            var template = new RabbitTemplate();
            var connectionFactory = new CachingConnectionFactory();
            connectionFactory.Port = BrokerTestUtils.GetPort();
            template.ConnectionFactory = connectionFactory;

            var blockingQueueConsumer = new BlockingQueueConsumer(connectionFactory, new DefaultMessagePropertiesConverter(), new ActiveObjectCounter<BlockingQueueConsumer>(), AcknowledgeModeUtils.AcknowledgeMode.Auto, true, 1, queue.Name);
            blockingQueueConsumer.Start();
            connectionFactory.Dispose();

            // TODO: make this into a proper assertion. An exception can be thrown here by the Rabbit client and printed to
            // stderr without being rethrown (so hard to make a test fail).
            blockingQueueConsumer.Stop();
            Assert.IsNull(template.ReceiveAndConvert(queue.Name));
        }
 private void TestRequeueOrNotDefaultNot(Exception ex, bool requeue)
 {
     var connectionFactory = new Mock<IConnectionFactory>();
     var channel = new Mock<IModel>();
     var blockingQueueConsumer = new BlockingQueueConsumer(
         connectionFactory.Object, 
         new DefaultMessagePropertiesConverter(), 
         new ActiveObjectCounter<BlockingQueueConsumer>(), 
         AcknowledgeModeUtils.AcknowledgeMode.Auto, 
         true, 
         1, 
         false, 
         "testQ");
     this.TestRequeueOrNotGuts(ex, requeue, channel, blockingQueueConsumer);
 }
 /// <summary>Initializes a new instance of the <see cref="InternalConsumer"/> class.</summary>
 /// <param name="channel">The channel.</param>
 /// <param name="outer">The outer.</param>
 public InternalConsumer(IModel channel, BlockingQueueConsumer outer) : base(channel)
 {
     this.outer = outer;
 }
        /// <summary>
        /// Gets the result.
        /// </summary>
        /// <param name="consumer">The consumer.</param>
        /// <returns>The result.</returns>
        /// <remarks></remarks>
        private string GetResult(BlockingQueueConsumer consumer)
        {
            var response = consumer.NextMessage(new TimeSpan(0, 0, 0, 20));
            if (response == null)
            {
                return null;
            }

            return (string)new SimpleMessageConverter().FromMessage(response);
        }
 /// <summary>
 /// Creates the consumer.
 /// </summary>
 /// <param name="accessor">The accessor.</param>
 /// <returns>The consumer.</returns>
 /// <remarks></remarks>
 private BlockingQueueConsumer CreateConsumer(RabbitAccessor accessor)
 {
     var consumer = new BlockingQueueConsumer(accessor.ConnectionFactory, new ActiveObjectCounter<BlockingQueueConsumer>(), AcknowledgeModeUtils.AcknowledgeMode.AUTO, true, 1, 0, queue.Name);
     consumer.Start();
     return consumer;
 }
 /// <summary>Initializes a new instance of the <see cref="AsyncMessageProcessingConsumer"/> class.</summary>
 /// <param name="consumer">The consumer.</param>
 /// <param name="outer">The outer.</param>
 public AsyncMessageProcessingConsumer(BlockingQueueConsumer consumer, SimpleMessageListenerContainer outer)
 {
     this.consumer = consumer;
     this.outer    = outer;
     this.start    = new CountdownEvent(1);
 }
        /// <summary>Receive and execute.</summary>
        /// <param name="consumer">The consumer.</param>
        /// <returns>True if a message was received.</returns>
        internal bool ReceiveAndExecute(BlockingQueueConsumer consumer)
        {
            if (this.transactionManager != null)
            {
                try
                {
                    var transactionTemplate = new TransactionTemplate(this.transactionManager);
                    transactionTemplate.PropagationBehavior = this.transactionAttribute.PropagationBehavior;
                    transactionTemplate.TransactionIsolationLevel = IsolationLevel.Unspecified; // TODO: revert to transactionAttribute once we take dependency on SPRNET 2.0
                    transactionTemplate.TransactionTimeout = this.transactionAttribute.TransactionTimeout;
                    transactionTemplate.ReadOnly = this.transactionAttribute.ReadOnly;
                    transactionTemplate.Name = this.transactionAttribute.Name;

                    return (bool)transactionTemplate.Execute(
                        status =>
                        {
                            ConnectionFactoryUtils.BindResourceToTransaction(new RabbitResourceHolder(consumer.Channel, false), this.ConnectionFactory, true);
                            return this.DoReceiveAndExecute(consumer);
                        });
                }
                catch (Exception ex)
                {
                    Logger.Error(m => m("Error receiving and executing."), ex);
                    throw;
                }
            }

            return this.DoReceiveAndExecute(consumer);
        }
        /// <summary>
        /// Perform receive and execute actions.
        /// </summary>
        /// <param name="consumer">
        /// The consumer.
        /// </param>
        /// <returns>
        /// True if a message was received.
        /// </returns>
        private bool DoReceiveAndExecute(BlockingQueueConsumer consumer)
        {
            var channel = consumer.Channel;

            Message lastMessage = null;
            for (var i = 0; i < this.txSize; i++)
            {
                this.logger.Trace("Waiting for message from consumer.");
                var message = consumer.NextMessage(new TimeSpan(0, 0, 0, 0, (int)this.receiveTimeout));
                if (message == null)
                {
                    break;
                }

                lastMessage = message;
                try
                {
                    this.ExecuteListener(channel, message);
                }
                catch (ImmediateAcknowledgeAmqpException e)
                {
                    break;
                }
                catch (Exception ex)
                {
                    this.RollbackOnExceptionIfNecessary(channel, message, ex);
                    throw;
                }
            }

            if (lastMessage != null)
            {
                this.CommitIfNecessary(channel, lastMessage);
                return true;
            }

            return false;
        }
        private void TestRequeueOrNotGuts(Exception ex, bool requeue, Mock<IModel> channel, BlockingQueueConsumer blockingQueueConsumer)
        {
            var channelField = typeof(BlockingQueueConsumer).GetField("channel", BindingFlags.NonPublic | BindingFlags.Instance);
            channelField.SetValue(blockingQueueConsumer, channel.Object);

            var deliveryTags = new LinkedList<long>();
            deliveryTags.AddOrUpdate(1L);
            var deliveryTagsField = typeof(BlockingQueueConsumer).GetField("deliveryTags", BindingFlags.NonPublic | BindingFlags.Instance);
            deliveryTagsField.SetValue(blockingQueueConsumer, deliveryTags);
            blockingQueueConsumer.RollbackOnExceptionIfNecessary(ex);
            channel.Verify(m => m.BasicReject(1L, requeue), Times.Once());
        }
        /// <summary>
        /// Restart the consumer.
        /// </summary>
        /// <param name="consumer">
        /// The consumer.
        /// </param>
        /// <exception cref="Exception">
        /// </exception>
        internal void Restart(BlockingQueueConsumer consumer)
        {
            lock (this.consumersMonitor)
            {
                if (this.consumers != null)
                {
                    try
                    {
                        // Need to recycle the channel in this consumer
                        consumer.Stop();

                        // Ensure consumer counts are correct (another is not going
                        // to start because of the exception, but
                        // we haven't counted down yet)
                        this.cancellationLock.Release(consumer);
                        this.consumers.Remove(consumer);
                        consumer = this.CreateBlockingQueueConsumer();
                        this.consumers.Add(consumer);
                    }
                    catch (Exception e)
                    {
                        this.logger.Warn("Consumer died on restart. " + e.Source + ": " + e.Message);

                        // Thrown into the void (probably) in a background thread.
                        // Oh well, here goes...
                        throw e;
                    }

                    this.taskExecutor.Execute(new AsyncMessageProcessingConsumer(consumer, this));
                }
            }
        }
        /// <summary>
        /// Receive and execute.
        /// </summary>
        /// <param name="consumer">
        /// The consumer.
        /// </param>
        /// <returns>
        /// True if a message was received.
        /// </returns>
        internal bool ReceiveAndExecute(BlockingQueueConsumer consumer)
        {
            if (this.transactionManager != null)
            {
                try
                {
                    return (bool)new TransactionTemplate(this.transactionManager).Execute(delegate(ITransactionStatus status)
                                                                                     {
                                                                                         ConnectionFactoryUtils.BindResourceToTransaction(new RabbitResourceHolder(consumer.Channel), this.ConnectionFactory, true);
                                                                                         try
                                                                                         {
                                                                                             return this.DoReceiveAndExecute(consumer);
                                                                                         }
                                                                                         catch (Exception e)
                                                                                         {
                                                                                             throw;
                                                                                         }
                                                                                     });
                }
                catch (Exception e)
                {
                    throw;
                }
            }

            return this.DoReceiveAndExecute(consumer);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="AsyncMessageProcessingConsumer"/> class.
 /// </summary>
 /// <param name="consumer">
 /// The consumer.
 /// </param>
 /// <param name="outer">
 /// The outer.
 /// </param>
 public AsyncMessageProcessingConsumer(BlockingQueueConsumer consumer, SimpleMessageListenerContainer outer)
 {
     this.consumer = consumer;
     this.outer = outer;
     this.start = new CountDownLatch(1);
 }
        /// <summary>Creates the consumer.</summary>
        /// <param name="accessor">The accessor.</param>
        /// <returns>The consumer.</returns>
        private BlockingQueueConsumer CreateConsumer(RabbitAccessor accessor)
        {
            var consumer = new BlockingQueueConsumer(accessor.ConnectionFactory, new DefaultMessagePropertiesConverter(), new ActiveObjectCounter<BlockingQueueConsumer>(), AcknowledgeModeUtils.AcknowledgeMode.Auto, true, 1, queue.Name);
            consumer.Start();

            // wait for consumeOk...
            var n = 0;
            while (n++ < 100)
            {
                if (consumer.ConsumerTag == null)
                {
                    try
                    {
                        Thread.Sleep(100);
                    }
                    catch (ThreadInterruptedException e)
                    {
                        Thread.CurrentThread.Interrupt();
                        break;
                    }
                }
            }

            return consumer;
        }
        /// <summary>Perform receive and execute actions.</summary>
        /// <param name="consumer">The consumer.</param>
        /// <returns>True if a message was received.</returns>
        private bool DoReceiveAndExecute(BlockingQueueConsumer consumer)
        {
            var channel = consumer.Channel;

            for (var i = 0; i < this.txSize; i++)
            {
                Logger.Trace(m => m("Waiting for message from consumer."));
                var message = consumer.NextMessage(this.receiveTimeout);
                if (message == null)
                {
                    break;
                }

                try
                {
                    this.ExecuteListener(channel, message);
                }
                catch (ImmediateAcknowledgeAmqpException e)
                {
                    Logger.Trace(m => m("DoReceiveAndExecute => "), e);
                    break;
                }
                catch (Exception ex)
                {
                    consumer.RollbackOnExceptionIfNecessary(ex);
                    throw;
                }
            }

            return consumer.CommitIfNecessary(this.IsChannelLocallyTransacted(channel));
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="InternalConsumer"/> class.
 /// </summary>
 /// <param name="channel">
 /// The channel.
 /// </param>
 /// <param name="outer">
 /// The outer.
 /// </param>
 public InternalConsumer(IModel channel, BlockingQueueConsumer outer)
     : base(channel)
 {
     this.outer = outer;
 }
        /// <summary>Restart the consumer.</summary>
        /// <param name="consumer">The consumer.</param>
        internal void Restart(BlockingQueueConsumer consumer)
        {
            lock (this.consumersMonitor)
            {
                if (this.consumers != null)
                {
                    try
                    {
                        // Need to recycle the channel in this consumer
                        consumer.Stop();

                        // Ensure consumer counts are correct (another is not going
                        // to start because of the exception, but
                        // we haven't counted down yet)
                        this.cancellationLock.Release(consumer);
                        this.consumers.Remove(consumer);
                        consumer = this.CreateBlockingQueueConsumer();
                        this.consumers.Add(consumer);
                    }
                    catch (Exception e)
                    {
                        Logger.Warn(m => m("Consumer failed irretrievably on restart. {0}: {1}", e.Source, e.Message));

                        // Re-throw and have it logged properly by the caller.
                        throw;
                    }

                    var processor = new AsyncMessageProcessingConsumer(consumer, this);
                    var taskExecutor = new Task(processor.Run);
                    taskExecutor.Start();
                }
            }
        }