Beispiel #1
0
        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);
                }
            }
        }
        protected override void DoBegin(object transaction, ITransactionDefinition definition)
        {
            if (definition.IsolationLevel != AbstractTransactionDefinition.ISOLATION_DEFAULT)
            {
                throw new InvalidIsolationLevelException("AMQP does not support an isolation level concept");
            }

            var txObject = (RabbitTransactionObject)transaction;
            RabbitResourceHolder resourceHolder = null;

            try
            {
                resourceHolder = ConnectionFactoryUtils.GetTransactionalResourceHolder(ConnectionFactory, true);
                _logger?.LogDebug("Created AMQP transaction on channel [" + resourceHolder.GetChannel() + "]");

                txObject.ResourceHolder = resourceHolder;
                txObject.ResourceHolder.SynchronizedWithTransaction = true;
                var timeout = DetermineTimeout(definition);
                if (timeout != AbstractTransactionDefinition.TIMEOUT_DEFAULT)
                {
                    txObject.ResourceHolder.SetTimeoutInSeconds(timeout);
                }

                TransactionSynchronizationManager.BindResource(ConnectionFactory, txObject.ResourceHolder);
            }
            catch (AmqpException ex)
            {
                if (resourceHolder != null)
                {
                    ConnectionFactoryUtils.ReleaseResources(resourceHolder);
                }

                throw new CannotCreateTransactionException("Could not create AMQP transaction", ex);
            }
        }
        public void TestTemplateUsesPublisherConnectionUnlessInTx()
        {
            connectionFactory.Destroy();
            template.UsePublisherConnection = true;
            template.ConvertAndSend("dummy", "foo");
            Assert.Null(connectionFactory._connection.Target);
            Assert.NotNull(((CachingConnectionFactory)connectionFactory.PublisherConnectionFactory)._connection.Target);
            connectionFactory.Destroy();
            Assert.Null(connectionFactory._connection.Target);
            Assert.Null(((CachingConnectionFactory)connectionFactory.PublisherConnectionFactory)._connection.Target);
            var channel = connectionFactory.CreateConnection().CreateChannel(true);

            Assert.NotNull(connectionFactory._connection.Target);
            var holder = new RabbitResourceHolder(channel, true);

            TransactionSynchronizationManager.BindResource(connectionFactory, holder);
            try
            {
                template.IsChannelTransacted = true;
                template.ConvertAndSend("dummy", "foo");
                Assert.NotNull(connectionFactory._connection.Target);
                Assert.Null(((CachingConnectionFactory)connectionFactory.PublisherConnectionFactory)._connection.Target);
            }
            finally
            {
                TransactionSynchronizationManager.UnbindResource(connectionFactory);
                channel.Close();
            }
        }
Beispiel #4
0
 protected virtual void PrepareHolderForRollback(RabbitResourceHolder resourceHolder, Exception exception)
 {
     if (resourceHolder != null)
     {
         resourceHolder.RequeueOnRollback = AlwaysRequeueWithTxManagerRollback ||
                                            ContainerUtils.ShouldRequeue(DefaultRequeueRejected, exception, _logger);
     }
 }
        public void TestChannelCloseInTx()
        {
            connectionFactory.IsPublisherReturns = false;
            var channel = connectionFactory.CreateConnection().CreateChannel(true);
            var holder  = new RabbitResourceHolder(channel, true);

            TransactionSynchronizationManager.BindResource(connectionFactory, holder);
            try
            {
                template.IsChannelTransacted = true;
                template.ConvertAndSend(ROUTE, "foo");
                template.ConvertAndSend(Guid.NewGuid().ToString(), ROUTE, "xxx");
                var n = 0;
                while (n++ < 100 && channel.IsOpen)
                {
                    Thread.Sleep(100);
                }

                Assert.False(channel.IsOpen);

                try
                {
                    template.ConvertAndSend(ROUTE, "bar");
                    throw new Exception("Expected exception");
                }
                catch (RabbitUncategorizedException e)
                {
                    if (e.InnerException is InvalidOperationException)
                    {
                        Assert.Contains("Channel closed during transaction", e.InnerException.Message);
                    }
                    else
                    {
                        throw new Exception("Expected InvalidOperationException");
                    }
                }
                catch (RabbitConnectException e)
                {
                    Assert.IsType <R.Exceptions.AlreadyClosedException>(e.InnerException);
                }
            }
            finally
            {
                TransactionSynchronizationManager.UnbindResource(connectionFactory);
                channel.Close();
            }
        }
        /// <summary>Invokes the specified listener</summary>
        /// <param name="channel">The channel to operate on.</param>
        /// <param name="message">The received message.</param>
        /// <see cref="MessageListener"/>
        public virtual void InvokeListener(IModel channel, Message message)
        {
            var listener = this.MessageListener;

            if (listener is IChannelAwareMessageListener)
            {
                this.DoInvokeListener((IChannelAwareMessageListener)listener, channel, message);
            }
            else if (listener is IMessageListener || listener is Action <Message> )
            {
                var bindChannel = this.ExposeListenerChannel && this.IsChannelLocallyTransacted(channel);
                if (bindChannel)
                {
                    var resourceHolder = new RabbitResourceHolder(channel, false);
                    resourceHolder.SynchronizedWithTransaction = true;
                    TransactionSynchronizationManager.BindResource(this.ConnectionFactory, resourceHolder);
                }

                try
                {
                    if (listener is IMessageListener)
                    {
                        this.DoInvokeListener((IMessageListener)listener, message);
                    }
                    else if (listener is Action <Message> )
                    {
                        this.DoInvokeListener((Action <Message>)listener, message);
                    }
                }
                finally
                {
                    if (bindChannel)
                    {
                        // unbind if we bound
                        TransactionSynchronizationManager.UnbindResource(this.ConnectionFactory);
                    }
                }
            }
            else if (listener != null)
            {
                throw new ArgumentException("Only MessageListener and SessionAwareMessageListener supported: " + listener);
            }
            else
            {
                throw new InvalidOperationException("No message listener specified - see property MessageListener");
            }
        }
Beispiel #7
0
        /// <summary>Do begin.</summary>
        /// <param name="transaction">The transaction.</param>
        /// <param name="definition">The definition.</param>
        protected override void DoBegin(object transaction, ITransactionDefinition definition)
        {
            // https://jira.springsource.org/browse/SPRNET-1444 (SPRNET 2.0) has default TransactionIsolationLevel as IsolationLevel.Unspecified, letting this work. Will not work for SPRNET <= 1.3.2.
            if (definition.TransactionIsolationLevel != IsolationLevel.Unspecified)
            {
                throw new InvalidIsolationLevelException("AMQP does not support an isolation level concept");
            }

            var transactionObject = (RabbitTransactionObject)transaction;
            RabbitResourceHolder resourceHolder = null;

            try
            {
                resourceHolder = ConnectionFactoryUtils.GetTransactionalResourceHolder(this.ConnectionFactory, true);
                Logger.Debug(m => m("Created AMQP transaction on channel [{0}]", resourceHolder.Channel));

                // resourceHolder.DeclareTransactional();
                transactionObject.ResourceHolder = resourceHolder;
                transactionObject.ResourceHolder.SynchronizedWithTransaction = true;
                var timeout = this.DetermineTimeout(definition);
                if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
                {
                    transactionObject.ResourceHolder.TimeoutInSeconds = timeout;
                }

                TransactionSynchronizationManager.BindResource(this.ConnectionFactory, transactionObject.ResourceHolder);
            }
            catch (AmqpException ex)
            {
                if (resourceHolder != null)
                {
                    ConnectionFactoryUtils.ReleaseResources(resourceHolder);
                }

                throw new CannotCreateTransactionException("Could not create AMQP transaction", ex);
            }
        }
Beispiel #8
0
        protected virtual void ActualInvokeListener(R.IModel channel, object data)
        {
            var listener = MessageListener;

            if (listener is IChannelAwareMessageListener chanListener)
            {
                DoInvokeListener(chanListener, channel, data);
            }
            else if (listener != null)
            {
                var bindChannel = ExposeListenerChannel && IsChannelLocallyTransacted;
                if (bindChannel)
                {
                    var resourceHolder = new RabbitResourceHolder(channel, false, _logger);
                    resourceHolder.SynchronizedWithTransaction = true;
                    TransactionSynchronizationManager.BindResource(ConnectionFactory, resourceHolder);
                }

                try
                {
                    DoInvokeListener(listener, data);
                }
                finally
                {
                    if (bindChannel)
                    {
                        // unbind if we bound
                        TransactionSynchronizationManager.UnbindResource(ConnectionFactory);
                    }
                }
            }
            else
            {
                throw new FatalListenerExecutionException("No message listener specified - see property 'messageListener'");
            }
        }
Beispiel #9
0
 /// <summary>Create the channel.</summary>
 /// <param name="holder">The rabbit resource holder.</param>
 /// <returns>The channel.</returns>
 protected IModel GetChannel(RabbitResourceHolder holder)
 {
     return(holder.Channel);
 }
Beispiel #10
0
 /// <summary>Fetch an appropriate Connection from the given RabbitResourceHolder.</summary>
 /// <param name="holder">The holder.</param>
 /// <returns>The connection.</returns>
 protected IConnection GetConnection(RabbitResourceHolder holder)
 {
     return(holder.Connection);
 }
 public RabbitTransactionObject(RabbitResourceHolder rabbitResourceHolder)
 {
     ResourceHolder = rabbitResourceHolder;
 }
Beispiel #12
0
        protected virtual void DoInvokeListener(IChannelAwareMessageListener listener, R.IModel channel, object data)
        {
            Message message = null;
            RabbitResourceHolder resourceHolder = null;
            var channelToUse = channel;
            var boundHere    = false;

            try
            {
                if (!ExposeListenerChannel)
                {
                    // We need to expose a separate Channel.
                    resourceHolder = GetTransactionalResourceHolder();
                    channelToUse   = resourceHolder.GetChannel();

                    /*
                     * If there is a real transaction, the resource will have been bound; otherwise
                     * we need to bind it temporarily here. Any work done on this channel
                     * will be committed in the finally block.
                     */
                    if (IsChannelLocallyTransacted &&
                        !TransactionSynchronizationManager.IsActualTransactionActive())
                    {
                        resourceHolder.SynchronizedWithTransaction = true;
                        TransactionSynchronizationManager.BindResource(ConnectionFactory, resourceHolder);
                        boundHere = true;
                    }
                }
                else
                {
                    // if locally transacted, bind the current channel to make it available to RabbitTemplate
                    if (IsChannelLocallyTransacted)
                    {
                        var localResourceHolder = new RabbitResourceHolder(channelToUse, false);
                        localResourceHolder.SynchronizedWithTransaction = true;
                        TransactionSynchronizationManager.BindResource(ConnectionFactory, localResourceHolder);
                        boundHere = true;
                    }
                }

                // Actually invoke the message listener...
                try
                {
                    if (data is List <Message> asList)
                    {
                        listener.OnMessageBatch(asList, channelToUse);
                    }
                    else
                    {
                        message = (Message)data;
                        listener.OnMessage(message, channelToUse);
                    }
                }
                catch (Exception e)
                {
                    _logger?.LogError("Exception in OnMessage call", e);
                    throw WrapToListenerExecutionFailedExceptionIfNeeded(e, data);
                }
            }
            finally
            {
                CleanUpAfterInvoke(resourceHolder, channelToUse, boundHere);
            }
        }
        /// <summary>Invoke the specified listener as Spring SessionAwareMessageListener,
        /// exposing a new Rabbit Channel (potentially with its own transaction)
        /// to the listener if demanded.</summary>
        /// <param name="listener">The Spring ISessionAwareMessageListener to invoke.</param>
        /// <param name="channel">The channel to operate on.</param>
        /// <param name="message">The received message.</param>
        /// <see cref="IChannelAwareMessageListener"/><see cref="ExposeListenerChannel"/>
        protected virtual void DoInvokeListener(IChannelAwareMessageListener listener, IModel channel, Message message)
        {
            RabbitResourceHolder resourceHolder = null;

            var channelToUse = channel;
            var boundHere    = false;

            try
            {
                if (!this.ExposeListenerChannel)
                {
                    // We need to expose a separate Channel.
                    resourceHolder = this.GetTransactionalResourceHolder();
                    channelToUse   = resourceHolder.Channel;

                    if (this.IsChannelLocallyTransacted(channelToUse) &&
                        !TransactionSynchronizationManager.ActualTransactionActive)
                    {
                        resourceHolder.SynchronizedWithTransaction = true;
                        TransactionSynchronizationManager.BindResource(
                            this.ConnectionFactory,
                            resourceHolder);
                        boundHere = true;
                    }
                }
                else
                {
                    // if locally transacted, bind the current channel to make it available to RabbitTemplate
                    if (this.IsChannelLocallyTransacted(channel))
                    {
                        var localResourceHolder = new RabbitResourceHolder(channelToUse, false);
                        localResourceHolder.SynchronizedWithTransaction = true;
                        TransactionSynchronizationManager.BindResource(this.ConnectionFactory, localResourceHolder);
                        boundHere = true;
                    }
                }

                // Actually invoke the message listener
                try
                {
                    listener.OnMessage(message, channelToUse);
                }
                catch (Exception e)
                {
                    throw this.WrapToListenerExecutionFailedExceptionIfNeeded(e);
                }
            }
            finally
            {
                if (resourceHolder != null && boundHere)
                {
                    // so the channel exposed (because exposeListenerChannel is false) will be closed
                    resourceHolder.SynchronizedWithTransaction = false;
                }

                ConnectionFactoryUtils.ReleaseResources(resourceHolder);
                if (boundHere)
                {
                    // unbind if we bound
                    TransactionSynchronizationManager.UnbindResource(this.ConnectionFactory);
                    if (!this.ExposeListenerChannel && this.IsChannelLocallyTransacted(channelToUse))
                    {
                        /*
                         *  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);
                    }
                }
            }
        }