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 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);
        }
示例#3
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);
                }
            }
        }
示例#4
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);
            }
        }
        /// <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);
                    }
                }
            }
        }