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); }
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); } } }
/// <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); } } } }