/// <summary>Obtain a RabbitMQ Channel that is synchronized with the current transaction, if any.</summary> /// <param name="connectionFactory">The connection factory.</param> /// <param name="resourceFactory">The resource factory.</param> /// <returns>The transactional Channel, or null if none found.</returns> private static RabbitResourceHolder DoGetTransactionalResourceHolder(IConnectionFactory connectionFactory, IResourceFactory resourceFactory) { AssertUtils.ArgumentNotNull(connectionFactory, "ConnectionFactory must not be null"); AssertUtils.ArgumentNotNull(resourceFactory, "ResourceFactory must not be null"); var resourceHolder = (RabbitResourceHolder)TransactionSynchronizationManager.GetResource(connectionFactory); if (resourceHolder != null) { var tempchannel = resourceFactory.GetChannel(resourceHolder); if (tempchannel != null) { return(resourceHolder); } } var resourceHolderToUse = resourceHolder; if (resourceHolderToUse == null) { resourceHolderToUse = new RabbitResourceHolder(); } var connection = resourceFactory.GetConnection(resourceHolderToUse); IModel channel = null; try { var isExistingCon = connection != null; if (!isExistingCon) { connection = resourceFactory.CreateConnection(); resourceHolderToUse.AddConnection(connection); } channel = consumerChannel.Value; if (channel == null) { channel = resourceFactory.CreateChannel(connection); } resourceHolderToUse.AddChannel(channel, connection); if (resourceHolderToUse != resourceHolder) { BindResourceToTransaction(resourceHolderToUse, connectionFactory, resourceFactory.IsSynchedLocalTransactionAllowed); } return(resourceHolderToUse); } catch (Exception ex) { RabbitUtils.CloseChannel(channel); RabbitUtils.CloseConnection(connection); throw new AmqpIOException(ex); } }
/// <summary>Release the resources.</summary> /// <param name="resourceHolder">The resource holder.</param> public static void ReleaseResources(RabbitResourceHolder resourceHolder) { if (resourceHolder == null || resourceHolder.SynchronizedWithTransaction) { return; } RabbitUtils.CloseChannel(resourceHolder.Channel); RabbitUtils.CloseConnection(resourceHolder.Connection); }
/// <summary> /// Bind a resource to a transaction. /// </summary> /// <param name="resourceHolder"> /// The resource holder. /// </param> /// <param name="connectionFactory"> /// The connection factory. /// </param> /// <param name="synched"> /// The synched. /// </param> public static void BindResourceToTransaction(RabbitResourceHolder resourceHolder, IConnectionFactory connectionFactory, bool synched) { if (TransactionSynchronizationManager.HasResource(connectionFactory) || !TransactionSynchronizationManager.ActualTransactionActive || !synched) { return; } TransactionSynchronizationManager.BindResource(connectionFactory, resourceHolder); resourceHolder.SynchronizedWithTransaction = true; if (TransactionSynchronizationManager.SynchronizationActive) { TransactionSynchronizationManager.RegisterSynchronization(new RabbitResourceSynchronization(resourceHolder, connectionFactory, synched)); } }
/// <summary>Bind a resource to a transaction.</summary> /// <param name="resourceHolder">The resource holder.</param> /// <param name="connectionFactory">The connection factory.</param> /// <param name="synched">The synched.</param> public static void BindResourceToTransaction(RabbitResourceHolder resourceHolder, IConnectionFactory connectionFactory, bool synched) { if (TransactionSynchronizationManager.HasResource(connectionFactory) || !TransactionSynchronizationManager.ActualTransactionActive || !synched) { return; } TransactionSynchronizationManager.BindResource(connectionFactory, resourceHolder); resourceHolder.SynchronizedWithTransaction = true; if (TransactionSynchronizationManager.SynchronizationActive) { TransactionSynchronizationManager.RegisterSynchronization(new RabbitResourceSynchronization(resourceHolder, connectionFactory, synched)); } }
/// <summary> /// Obtain a RabbitMQ Channel that is synchronized with the current transaction, if any. /// </summary> /// <param name="connectionFactory"> /// The connection factory. /// </param> /// <param name="resourceFactory"> /// The resource factory. /// </param> /// <returns> /// The transactional Channel, or null if none found. /// </returns> /// <exception cref="AmqpException"> /// </exception> private static RabbitResourceHolder DoGetTransactionalResourceHolder(IConnectionFactory connectionFactory, IResourceFactory resourceFactory) { AssertUtils.ArgumentNotNull(connectionFactory, "ConnectionFactory must not be null"); AssertUtils.ArgumentNotNull(resourceFactory, "ResourceFactory must not be null"); var resourceHolder = (RabbitResourceHolder)TransactionSynchronizationManager.GetResource(connectionFactory); if (resourceHolder != null) { var tempchannel = resourceFactory.GetChannel(resourceHolder); if (tempchannel != null) { return resourceHolder; } } var resourceHolderToUse = resourceHolder; if (resourceHolderToUse == null) { resourceHolderToUse = new RabbitResourceHolder(); } var connection = resourceFactory.GetConnection(resourceHolderToUse); IModel channel = null; try { bool isExistingCon = connection != null; if (!isExistingCon) { connection = resourceFactory.CreateConnection(); resourceHolderToUse.AddConnection(connection); } channel = resourceFactory.CreateChannel(connection); resourceHolderToUse.AddChannel(channel, connection); if (resourceHolderToUse != resourceHolder) { BindResourceToTransaction(resourceHolderToUse, connectionFactory, resourceFactory.IsSynchedLocalTransactionAllowed); } return resourceHolderToUse; } catch (Exception ex) { RabbitUtils.CloseChannel(channel); RabbitUtils.CloseConnection(connection); throw; } }
/// <summary> /// Release the resources. /// </summary> /// <param name="resourceHolder"> /// The resource holder. /// </param> public static void ReleaseResources(RabbitResourceHolder resourceHolder) { if (resourceHolder == null || resourceHolder.SynchronizedWithTransaction) { return; } RabbitUtils.CloseChannel(resourceHolder.Channel); ReleaseConnection(resourceHolder.Connection); }
/// <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; }
/// <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; }
/// <summary> /// Process resources after commit. /// </summary> /// <param name="resourceHolder"> /// The resource holder. /// </param> protected void ProcessResourceAfterCommit(RabbitResourceHolder resourceHolder) { resourceHolder.CommitAll(); }
/// <summary>Gets a connection.</summary> /// <param name="holder">The holder.</param> /// <returns>The connection.</returns> public IConnection GetConnection(RabbitResourceHolder holder) { return holder.Connection; }
/// <summary>Gets a channel.</summary> /// <param name="holder">The holder.</param> /// <returns>The channel.</returns> public IModel GetChannel(RabbitResourceHolder holder) { return holder.Channel; }
/// <summary> /// Create the channel. /// </summary> /// <param name="holder"> /// The rabbit resource holder. /// </param> /// <returns> /// The channel. /// </returns> protected RabbitMQ.Client.IModel GetChannel(RabbitResourceHolder holder) { return holder.Channel; }
/// <summary>Gets a connection.</summary> /// <param name="holder">The holder.</param> /// <returns>The connection.</returns> public IConnection GetConnection(RabbitResourceHolder holder) { return(holder.Connection); }
/// <summary>Gets a channel.</summary> /// <param name="holder">The holder.</param> /// <returns>The channel.</returns> public IModel GetChannel(RabbitResourceHolder holder) { return(holder.Channel); }
/// <summary> /// Release the resource. /// </summary> /// <param name="resourceHolder"> /// The resource holder. /// </param> /// <param name="resourceKey"> /// The resource key. /// </param> protected void ReleaseResource(RabbitResourceHolder resourceHolder, object resourceKey) { ConnectionFactoryUtils.ReleaseResources(resourceHolder); }
/// <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"); } }
/// <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); } } } }
/// <summary> /// Initializes a new instance of the <see cref="RabbitResourceSynchronization"/> class. /// </summary> /// <param name="resourceHolder"> /// The resource holder. /// </param> /// <param name="resourceKey"> /// The resource key. /// </param> /// <param name="transacted"> /// The transacted. /// </param> public RabbitResourceSynchronization(RabbitResourceHolder resourceHolder, object resourceKey, bool transacted) { //super(resourceHolder, resourceKey); this.resourceHolder = resourceHolder; this.transacted = transacted; }