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);
            }
        }
Exemple #2
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);
            }
        }