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 [{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 (RabbitException ex)
            {
                if (resourceHolder != null)
                {
                    ConnectionFactoryUtils.ReleaseResources(resourceHolder);
                }

                throw new CannotCreateTransactionException("Could not create AMQP transaction", ex);
            }
        }
        /// <summary>
        /// Initializes this container.  Creates a Connection, starts the Connection
        /// (if the property <see cref="AutoStartup"/> hasn't been turned off), and calls
        /// <see cref="DoInitialize"/>.
        /// </summary>
        /// <exception cref="EMSException">If startup failed</exception>
        public virtual void Initialize()
        {
            try
            {
                lock (this.lifecycleMonitor)
                {
                    this.active = true;
                    System.Threading.Monitor.PulseAll(this.lifecycleMonitor);
                }

                if (this.autoStartup)
                {
                    DoStart();
                }

                DoInitialize();
            }
            catch (Exception)
            {
                lock (this.sharedConnectionMonitor)
                {
                    ConnectionFactoryUtils.ReleaseConnection(sharedConnection, ConnectionFactory, autoStartup);
                }
                throw;
            }
        }
Пример #3
0
        private IMessage Handle(Delivery delivery)
        {
            if (delivery == null && Shutdown != null)
            {
                throw new ShutdownSignalException(Shutdown);
            }

            if (delivery == null)
            {
                return(null);
            }

            var body = delivery.Body;
            var messageProperties = MessageHeadersConverter.ToMessageHeaders(delivery.Properties, delivery.Envelope, EncodingUtils.Utf8);
            var accesor           = RabbitHeaderAccessor.GetMutableAccessor(messageProperties);

            accesor.ConsumerTag   = delivery.ConsumerTag;
            accesor.ConsumerQueue = delivery.Queue;
            var message = Message.Create(body, accesor.MessageHeaders);

            Logger?.LogDebug("Received message: {message}", message);
            if (messageProperties.DeliveryTag() != null)
            {
                DeliveryTags.Add(messageProperties.DeliveryTag().Value);
            }

            if (Transactional && !LocallyTransacted)
            {
                ConnectionFactoryUtils.RegisterDeliveryTag(ConnectionFactory, Channel, delivery.Envelope.DeliveryTag);
            }

            return(message);
        }
Пример #4
0
        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);
        }
 /// <summary>
 /// Refreshes the shared connection that this container holds.
 /// </summary>
 /// <remarks>
 /// Called on startup and also after an infrastructure exception
 /// that occurred during invoker setup and/or execution.
 /// </remarks>
 /// <exception cref="NMSException">If thrown by NMS API methods</exception>
 protected void RefreshSharedConnection()
 {
     lock (sharedConnectionMonitor)
     {
         ConnectionFactoryUtils.ReleaseConnection(sharedConnection, ConnectionFactory, sharedConnectionStarted);
         sharedConnection = CreateSharedConnection();
         if (sharedConnectionStarted)
         {
             sharedConnection.Start();
         }
     }
 }
        /// <summary>Perform a commit or message acknowledgement, as appropriate</summary>
        /// <param name="locallyTransacted">if set to <c>true</c> [locally transacted].</param>
        /// <returns>True if committed, else false.</returns>
        public bool CommitIfNecessary(bool locallyTransacted)
        {
            if (this.deliveryTags == null || this.deliveryTags.Count < 1)
            {
                return(false);
            }

            try
            {
                var ackRequired = !this.acknowledgeMode.IsAutoAck() && !this.acknowledgeMode.IsManual();

                if (ackRequired)
                {
                    if (this.transactional && !locallyTransacted)
                    {
                        // Not locally transacted but it is transacted so it
                        // could be synchronized with an external transaction
                        foreach (var deliveryTag in this.deliveryTags)
                        {
                            ConnectionFactoryUtils.RegisterDeliveryTag(this.connectionFactory, this.channel, deliveryTag);
                        }
                    }
                    else
                    {
                        if (this.deliveryTags != null && this.deliveryTags.Count > 0)
                        {
                            var copiedTags = new List <long>(this.deliveryTags);
                            if (copiedTags.Count > 0)
                            {
                                var deliveryTag = copiedTags[copiedTags.Count - 1];
                                this.channel.BasicAck((ulong)deliveryTag, true);
                            }
                        }
                    }
                }

                if (locallyTransacted)
                {
                    // For manual acks we still need to commit
                    RabbitUtils.CommitIfNecessary(this.channel);
                }
            }
            finally
            {
                this.deliveryTags.Clear();
            }

            return(true);
        }
        private Apache.NMS.IMessage SendAndReceive(IMessage requestMessage)
        {
            IConnection      connection      = CreateConnection();
            ISession         session         = null;
            IMessageProducer messageProducer = null;
            IMessageConsumer messageConsumer = null;
            IDestination     replyTo         = null;

            try
            {
                session = CreateSession(connection);
                Apache.NMS.IMessage jmsRequest = this.messageConverter.ToMessage(requestMessage, session);
                messageProducer = session.CreateProducer(this.GetRequestDestination(session));
                messageProducer.DeliveryMode = deliveryMode;
                messageProducer.Priority     = priority;
                messageProducer.TimeToLive   = timeToLive;
                replyTo = GetReplyDestination(session);
                jmsRequest.NMSReplyTo = replyTo;
                connection.Start();
                messageProducer.Send(jmsRequest);
                if (replyTo is ITemporaryQueue || replyTo is ITemporaryTopic)
                {
                    messageConsumer = session.CreateConsumer(replyTo);
                }
                else
                {
                    String messageId       = jmsRequest.NMSMessageId.Replace("'", "''");
                    String messageSelector = "NMSCorrelationID = '" + messageId + "'";
                    messageConsumer = session.CreateConsumer(replyTo, messageSelector);
                }
                return((TimeSpan.Compare(receiveTimeout, TimeSpan.FromMilliseconds(0)) == 1)
                           ? messageConsumer.Receive(receiveTimeout)
                           : messageConsumer.Receive());
            }
            finally
            {
                NmsUtils.CloseMessageProducer(messageProducer);
                NmsUtils.CloseMessageConsumer(messageConsumer);
                this.DeleteDestinationIfTemporary(session, replyTo);
                NmsUtils.CloseSession(session);

                ConnectionFactoryUtils.ReleaseConnection(connection, this.connectionFactory, true);
            }
        }
Пример #8
0
        public void Start()
        {
            Logger?.LogDebug("Starting consumer {consumer}", ToString());
            try
            {
                ResourceHolder = ConnectionFactoryUtils.GetTransactionalResourceHolder(ConnectionFactory, Transactional);
                Channel        = ResourceHolder.GetChannel();

                // ClosingRecoveryListener.AddRecoveryListenerIfNecessary(Channel);
            }
            catch (RabbitAuthenticationException e)
            {
                throw new FatalListenerStartupException("Authentication failure", e);
            }

            DeliveryTags.Clear();
            ActiveObjectCounter.Add(this);
            PassiveDeclarations();
            SetQosAndCreateConsumers();
        }
        public void TestReceiveBlockingGlobalTx()
        {
            template.ConvertAndSend(ROUTE, "blockGTXNoTO");
            var resourceHolder = ConnectionFactoryUtils
                                 .GetTransactionalResourceHolder(template.ConnectionFactory, true);

            TransactionSynchronizationManager.SetActualTransactionActive(true);
            ConnectionFactoryUtils.BindResourceToTransaction(resourceHolder, template.ConnectionFactory, true);
            template.ReceiveTimeout      = -1;
            template.IsChannelTransacted = true;
            var o = template.ReceiveAndConvert <string>(ROUTE);

            resourceHolder.CommitAll();
            resourceHolder.CloseAll();
            Assert.Same(resourceHolder, TransactionSynchronizationManager.UnbindResource(template.ConnectionFactory));
            Assert.NotNull(o);
            Assert.Equal("blockGTXNoTO", o);
            template.ReceiveTimeout = 0;
            Assert.Null(template.Receive(ROUTE));
        }
Пример #10
0
            private void ExecuteListenerInTransaction(Message message, ulong deliveryTag)
            {
                if (IsRabbitTxManager)
                {
                    ConsumerChannelRegistry.RegisterConsumerChannel(Model, ConnectionFactory);
                }

                if (TransactionTemplate == null)
                {
                    TransactionTemplate = new TransactionTemplate(TransactionManager, TransactionAttribute);
                }

                TransactionTemplate.Execute <object>(s =>
                {
                    var resourceHolder = ConnectionFactoryUtils.BindResourceToTransaction(new RabbitResourceHolder(Model, false), ConnectionFactory, true);
                    if (resourceHolder != null)
                    {
                        resourceHolder.AddDeliveryTag(Model, deliveryTag);
                    }

                    // unbound in ResourceHolderSynchronization.beforeCompletion()
                    try
                    {
                        CallExecuteListener(message, deliveryTag);
                    }
                    catch (Exception e1)
                    {
                        _container.PrepareHolderForRollback(resourceHolder, e1);
                        throw;
                    }

                    // catch (Throwable e2)
                    // {
                    //    //NOSONAR ok to catch Throwable here because we re-throw it below
                    //    throw new WrappedTransactionException(e2);
                    // }
                    return(null);
                });
            }
        /// <summary>
        /// Stop the shared connection, call <see cref="DoShutdown"/>, and close this container.
        /// </summary>
        public virtual void Shutdown()
        {
            logger.Debug("Shutting down message listener container");
            bool wasRunning = false;

            lock (this.lifecycleMonitor)
            {
                wasRunning   = this.running;
                this.running = false;
                this.active  = false;
                System.Threading.Monitor.PulseAll(this.lifecycleMonitor);
            }

            if (wasRunning && SharedConnectionEnabled)
            {
                try
                {
                    StopSharedConnection();
                } catch (Exception ex)
                {
                    logger.Debug("Could not stop NMS Connection on shutdown", ex);
                }
            }

            // Shut down the invokers
            try
            {
                DoShutdown();
            }
            finally
            {
                lock (this.sharedConnectionMonitor)
                {
                    ConnectionFactoryUtils.ReleaseConnection(this.sharedConnection, ConnectionFactory, false);
                }
            }
        }
Пример #12
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);
            }
        }
Пример #13
0
        public void SessionCallbackWithinSynchronizedTransaction()
        {
            SingleConnectionFactory scf      = new SingleConnectionFactory(mockConnectionFactory);
            NmsTemplate             template = CreateTemplate();

            template.ConnectionFactory = scf;

            mockConnection.Start();
            LastCall.On(mockConnection).Repeat.Times(2);
            // We're gonna call getTransacted 3 times, i.e. 2 more times.
            Expect.Call(mockSession.Transacted).Return(UseTransactedSession).Repeat.Twice();

            if (UseTransactedTemplate)
            {
                mockSession.Commit();
                LastCall.On(mockSession).Repeat.Once();
            }

            mockSession.Close();
            LastCall.On(mockSession).Repeat.Once();
            mockConnection.Stop();
            LastCall.On(mockConnection).Repeat.Once();
            mockConnection.Close();
            LastCall.On(mockConnection).Repeat.Once();

            mocks.ReplayAll();


            TransactionSynchronizationManager.InitSynchronization();

            try
            {
                template.Execute(session =>
                {
                    bool b = session.Transacted;
                    return(null);
                });
                template.Execute(session =>
                {
                    bool b = session.Transacted;
                    return(null);
                });

                Assert.AreSame(mockSession, ConnectionFactoryUtils.GetTransactionalSession(scf, null, false));
                Assert.AreSame(mockSession,
                               ConnectionFactoryUtils.GetTransactionalSession(scf, scf.CreateConnection(), false));

                //In Java this test was doing 'double-duty' and testing TransactionAwareConnectionFactoryProxy, which has
                //not been implemented in .NET

                template.Execute(session =>
                {
                    bool b = session.Transacted;
                    return(null);
                });

                IList synchs = TransactionSynchronizationManager.Synchronizations;
                Assert.AreEqual(1, synchs.Count);
                ITransactionSynchronization synch = (ITransactionSynchronization)synchs[0];
                synch.BeforeCommit(false);
                synch.BeforeCompletion();
                synch.AfterCommit();
                synch.AfterCompletion(TransactionSynchronizationStatus.Unknown);
            }
            finally
            {
                TransactionSynchronizationManager.ClearSynchronization();
                //Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0);
                //Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive);
                scf.Dispose();
            }
            Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0);
            mocks.VerifyAll();
        }
        /// <summary>The start.</summary>
        public void Start()
        {
            Logger.Debug(m => m("Starting consumer {0}", this));

            this.channel  = ConnectionFactoryUtils.GetTransactionalResourceHolder(this.connectionFactory, this.transactional).Channel;
            this.consumer = new InternalConsumer(this.channel, this);
            this.deliveryTags.Clear();
            this.activeObjectCounter.Add(this);
            var passiveDeclareTries = 3; // mirrored queue might be being moved

            while (passiveDeclareTries > 0)
            {
                passiveDeclareTries--;
                try
                {
                    if (!this.acknowledgeMode.IsAutoAck())
                    {
                        // Set basicQos before calling basicConsume (otherwise if we are not acking the broker
                        // will send blocks of 100 messages)
                        // The Java client includes a convenience method BasicQos(ushort prefetchCount), which sets 0 as the prefetchSize and false as global
                        this.channel.BasicQos(0, (ushort)this.prefetchCount, false);
                    }

                    foreach (var t in this.queues)
                    {
                        this.channel.QueueDeclarePassive(t);
                    }

                    passiveDeclareTries = 0;
                }
                catch (Exception e)
                {
                    if (passiveDeclareTries > 0 && this.channel.IsOpen)
                    {
                        Logger.Warn(m => m("Reconnect failed; retries left=" + (passiveDeclareTries - 1)), e);
                        try
                        {
                            Thread.Sleep(5000);
                        }
                        catch (ThreadInterruptedException e1)
                        {
                            Thread.CurrentThread.Interrupt();
                        }
                    }
                    else
                    {
                        this.activeObjectCounter.Release(this);
                        throw new FatalListenerStartupException("Cannot prepare queue for listener. Either the queue doesn't exist or the broker will not allow us to use it.", e);
                    }
                }
            }

            try
            {
                foreach (var t in this.queues)
                {
                    this.channel.BasicConsume(t, this.acknowledgeMode.IsAutoAck(), this.consumer);
                    Logger.Debug(m => m("Started on queue '{0}': {1}", t, this));
                }
            }
            catch (Exception e)
            {
                throw RabbitUtils.ConvertRabbitAccessException(e);
            }
        }
Пример #15
0
 /// <summary>
 /// Get a transactional resource holder.
 /// </summary>
 /// <returns>
 /// The rabbit resource holder.
 /// </returns>
 protected RabbitResourceHolder GetTransactionalResourceHolder()
 {
     return(ConnectionFactoryUtils.GetTransactionalResourceHolder(this.connectionFactory, this.ChannelTransacted));
 }
        /// <summary>
        /// Execute Run.
        /// </summary>
        public void Run()
        {
            var aborted = false;

            try
            {
                try
                {
                    this.consumer.Start();
                    this.start.Signal();
                }
                catch (FatalListenerStartupException ex)
                {
                    throw;
                }
                catch (Exception t)
                {
                    if (this.start.CurrentCount > 0)
                    {
                        this.start.Signal();
                    }

                    this.outer.HandleStartupFailure(t);
                    throw;
                }

                if (this.outer.transactionManager != null)
                {
                    // Register the consumer's channel so it will be used by the transaction manager
                    // if it's an instance of RabbitTransactionManager.
                    ConnectionFactoryUtils.RegisterConsumerChannel(this.consumer.Channel);
                }

                // Always better to stop receiving as soon as possible if
                // transactional
                var continuable = false;
                while (this.outer.IsActive || continuable)
                {
                    try
                    {
                        // Will come back false when the queue is drained
                        continuable = this.outer.ReceiveAndExecute(this.consumer) && !this.outer.ChannelTransacted;
                    }
                    catch (ListenerExecutionFailedException ex)
                    {
                        Logger.Trace(m => m("Error on ReceiveAndExecute"), ex);

                        // Continue to process, otherwise re-throw
                    }
                }
            }
            catch (ThreadInterruptedException e)
            {
                Logger.Debug(m => m("Consumer thread interrupted, processing stopped."));
                Thread.CurrentThread.Interrupt();
                aborted = true;
            }
            catch (FatalListenerStartupException ex)
            {
                Logger.Error(m => m("Consumer received fatal exception on startup", ex));
                this.startupException = ex;

                // Fatal, but no point re-throwing, so just abort.
                aborted = true;
            }
            catch (FatalListenerExecutionException ex)
            {
                Logger.Error(m => m("Consumer received fatal exception during processing"), ex);

                // Fatal, but no point re-throwing, so just abort.
                aborted = true;
            }
            catch (Exception t)
            {
                Logger.Warn(m => m("Consumer raised exception, processing can restart if the connection factory supports it. " + "Exception summary: " + t));
            }
            finally
            {
                if (this.outer.transactionManager != null)
                {
                    ConnectionFactoryUtils.UnRegisterConsumerChannel();
                }
            }

            // In all cases count down to allow container to progress beyond startup
            if (this.start.CurrentCount > 0)
            {
                this.start.Signal();
            }

            if (!this.outer.IsActive || aborted)
            {
                Logger.Debug(m => m("Cancelling {0}", this.consumer));
                try
                {
                    this.consumer.Stop();
                }
                catch (AmqpException e)
                {
                    Logger.Info(m => m("Could not cancel message consumer"), e);
                }

                if (aborted)
                {
                    Logger.Info(m => m("Stopping container from aborted consumer"));
                    this.outer.Stop();
                }
            }
            else
            {
                Logger.Info(m => m("Restarting {0}", this.consumer));
                this.outer.Restart(this.consumer);
            }
        }
        /// <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);
                    }
                }
            }
        }