Beispiel #1
0
        public static void CloseMessageConsumer(IModel channel, List <string> consumerTags, bool transactional, ILogger logger = null)
        {
            if (!channel.IsOpen)
            {
                return;
            }

            try
            {
                foreach (var consumerTag in consumerTags)
                {
                    Cancel(channel, consumerTag);
                }

                if (transactional)
                {
                    // Re-queue in-flight messages if any (after the consumer is cancelled to prevent the broker from simply
                    // sending them back to us). Does not require a tx.commit.
                    channel.BasicRecover(true);
                }

                // If not transactional then we are auto-acking (at least as of 1.0.0.M2) so there is nothing to recover.
                // Messages are going to be lost in general.
            }
            catch (Exception ex)
            {
                logger?.LogError(ex, "Exception during CloseMessageConsumer");

                throw RabbitExceptionTranslator.ConvertRabbitAccessException(ex);
            }
        }
        private void SetQosAndCreateConsumers()
        {
            if (!AcknowledgeMode.IsAutoAck() && !Cancelled)
            {
                // Set basicQos before calling basicConsume (otherwise if we are not acking the broker
                // will send blocks of 100 messages)
                try
                {
                    Channel.BasicQos(0, PrefetchCount, true);
                }
                catch (Exception e)
                {
                    ActiveObjectCounter.Release(this);
                    throw new RabbitIOException(e);
                }
            }

            try
            {
                if (!Cancelled)
                {
                    foreach (var queueName in Queues)
                    {
                        if (!MissingQueues.Contains(queueName))
                        {
                            ConsumeFromQueue(queueName);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(e);
            }
        }
Beispiel #3
0
        public void RollbackAll()
        {
            foreach (var channel in _channels)
            {
                _logger?.LogDebug("Rolling back messages to channel: {channel}", channel);

                RabbitUtils.RollbackIfNecessary(channel);
                if (_deliveryTags.TryGetValue(channel, out var tags))
                {
                    foreach (var deliveryTag in tags)
                    {
                        try
                        {
                            channel.BasicReject(deliveryTag, RequeueOnRollback);
                        }
                        catch (Exception ex)
                        {
                            _logger?.LogError(ex, "Error Rolling back messages to {channel} ", channel);
                            throw RabbitExceptionTranslator.ConvertRabbitAccessException(ex);
                        }
                    }

                    // Need to commit the reject (=nack)
                    RabbitUtils.CommitIfNecessary(channel);
                }
            }
        }
        protected virtual IConnection CreateBareConnection()
        {
            try
            {
                var connectionName = ObtainNewConnectionName();

                var rabbitConnection = Connect(connectionName);

                var connection = new SimpleConnection(rabbitConnection, CloseTimeout, _logger);

                _logger?.LogInformation("Created new connection: " + connectionName + "/" + connection);

                if (rabbitConnection != null && RecoveryListener != null)
                {
                    rabbitConnection.RecoverySucceeded       += RecoveryListener.HandleRecoverySucceeded;
                    rabbitConnection.ConnectionRecoveryError += RecoveryListener.HandleConnectionRecoveryError;
                }

                if (rabbitConnection != null && BlockedListener != null)
                {
                    rabbitConnection.ConnectionBlocked   += BlockedListener.HandleBlocked;
                    rabbitConnection.ConnectionUnblocked += BlockedListener.HandleUnblocked;
                }

                return(connection);
            }
            catch (Exception e) when(e is IOException || e is TimeoutException)
            {
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(e);
            }
        }
        protected void SendResponse(RC.IModel channel, Address replyTo, IMessage <byte[]> messageIn)
        {
            var message = messageIn;

            if (BeforeSendReplyPostProcessors != null)
            {
                var      processors    = BeforeSendReplyPostProcessors;
                IMessage postProcessed = message;
                foreach (var postProcessor in processors)
                {
                    postProcessed = postProcessor.PostProcessMessage(postProcessed);
                }

                message = postProcessed as IMessage <byte[]>;
                if (message == null)
                {
                    throw new InvalidOperationException("A BeforeSendReplyPostProcessors failed to return IMessage<byte[]>");
                }
            }

            PostProcessChannel(channel, message);

            try
            {
                _logger?.LogDebug("Publishing response to exchange = [{exchange}], routingKey = [{routingKey}]", replyTo.ExchangeName, replyTo.RoutingKey);
                if (RetryTemplate == null)
                {
                    DoPublish(channel, replyTo, message);
                }
                else
                {
                    var messageToSend = message;
                    RetryTemplate.Execute <object>(
                        ctx =>
                    {
                        DoPublish(channel, replyTo, messageToSend);
                        return(null);
                    },
                        ctx =>
                    {
                        if (RecoveryCallback != null)
                        {
                            ctx.SetAttribute(SendRetryContextAccessor.MESSAGE, messageToSend);
                            ctx.SetAttribute(SendRetryContextAccessor.ADDRESS, replyTo);
                            RecoveryCallback.Recover(ctx);
                            return(null);
                        }
                        else
                        {
                            throw RabbitExceptionTranslator.ConvertRabbitAccessException(ctx.LastException);
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(ex);
            }
        }
        public override void OnMessageBatch(List <IMessage> messages, IModel channel)
        {
            IMessage converted = null;

            if (IsMessageByteArrayList)
            {
                var list = new List <IMessage <byte[]> >();
                foreach (var m in messages)
                {
                    list.Add((IMessage <byte[]>)m);
                }

                converted = Message.Create(list);
            }
            else
            {
                if (IsMessageList)
                {
                    var messagingMessages = CreateMessageList(InferredArgumentType);
                    foreach (var message in messages)
                    {
                        messagingMessages.Add(ToMessagingMessage(message));
                    }

                    converted = Message.Create(messagingMessages);
                }
                else
                {
                    var payloads = CreateList(InferredArgumentType);

                    foreach (var message in messages)
                    {
                        PreprocesMessage(message);
                        var convertedObject = MessageConverter.FromMessage(message, InferredArgumentType);
                        if (convertedObject == null)
                        {
                            throw new MessageConversionException("Message converter returned null");
                        }

                        payloads.Add(convertedObject);
                    }

                    converted = Message.Create(payloads);
                }
            }

            try
            {
                InvokeHandlerAndProcessResult(null, channel, converted);
            }
            catch (Exception e)
            {
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(e);
            }
        }
        protected override object DoReceive()
        {
            var connection = ConnectionFactory.CreateConnection();
            var channel    = connection.CreateChannel(Transacted);

            try
            {
                var resp = channel.BasicGet(QueueName, false);
                if (resp == null)
                {
                    RabbitUtils.CloseChannel(channel);
                    RabbitUtils.CloseConnection(connection);
                    return(null);
                }

                var callback          = AckCallbackFactory.CreateCallback(new RabbitAckInfo(connection, channel, Transacted, resp));
                var envelope          = new Envelope(resp.DeliveryTag, resp.Redelivered, resp.Exchange, resp.RoutingKey);
                var messageProperties = MessageHeaderConverter.ToMessageHeaders(resp.BasicProperties, envelope, EncodingUtils.Utf8);
                var accessor          = RabbitHeaderAccessor.GetMutableAccessor(messageProperties);
                accessor.ConsumerQueue = this.QueueName;

                // Map<String, Object> headers = this.headerMapper.toHeadersFromRequest(messageProperties);
                var message = Message.Create <byte[]>(resp.Body, accessor.MessageHeaders);

                object payload;
                if (BatchingStrategy.CanDebatch(message.Headers))
                {
                    var payloads = new List <object>();
                    BatchingStrategy.DeBatch(message, fragment => payloads.Add(MessageConverter.FromMessage(fragment, null)));
                    payload = payloads;
                }
                else
                {
                    payload = MessageConverter.FromMessage(message, null);
                }

                var builder = MessageBuilderFactory.WithPayload(payload)
                              .CopyHeaders(accessor.MessageHeaders)
                              .SetHeader(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK, callback);
                if (RawMessageHeader)
                {
                    builder.SetHeader(RabbitMessageHeaderErrorMessageStrategy.AMQP_RAW_MESSAGE, message);
                    builder.SetHeader(IntegrationMessageHeaderAccessor.SOURCE_DATA, message);
                }

                return(builder);
            }
            catch (Exception e)
            {
                RabbitUtils.CloseChannel(channel);
                RabbitUtils.CloseConnection(connection);
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(e);
            }
        }
Beispiel #8
0
 public static void DeclareTransactional(IModel channel, ILogger logger = null)
 {
     try
     {
         channel.TxSelect();
     }
     catch (IOException e)
     {
         logger?.LogDebug(e, "Error performing 'txSelect' on {channel}", channel);
         throw RabbitExceptionTranslator.ConvertRabbitAccessException(e);
     }
 }
Beispiel #9
0
        protected void SendResponse(IModel channel, Address replyTo, Message messageIn)
        {
            var message = messageIn;

            if (BeforeSendReplyPostProcessors != null)
            {
                var processors = BeforeSendReplyPostProcessors;
                foreach (var postProcessor in processors)
                {
                    message = postProcessor.PostProcessMessage(message);
                }
            }

            PostProcessChannel(channel, message);

            try
            {
                _logger?.LogDebug("Publishing response to exchange = [" + replyTo.ExchangeName + "], routingKey = [" + replyTo.RoutingKey + "]");
                if (RetryTemplate == null)
                {
                    DoPublish(channel, replyTo, message);
                }
                else
                {
                    var messageToSend = message;
                    RetryTemplate.Execute <object>(
                        ctx =>
                    {
                        DoPublish(channel, replyTo, messageToSend);
                        return(null);
                    },
                        ctx =>
                    {
                        if (RecoveryCallback != null)
                        {
                            ctx.SetAttribute(SendRetryContextAccessor.MESSAGE, messageToSend);
                            ctx.SetAttribute(SendRetryContextAccessor.ADDRESS, replyTo);
                            RecoveryCallback.Recover(ctx);
                            return(null);
                        }
                        else
                        {
                            throw RabbitExceptionTranslator.ConvertRabbitAccessException(ctx.LastException);
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(ex);
            }
        }
Beispiel #10
0
        public static void RollbackIfNecessary(IModel channel, ILogger logger = null)
        {
            if (channel == null)
            {
                throw new ArgumentNullException(nameof(channel));
            }

            try
            {
                channel.TxRollback();
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Error during TxCommit");
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(ex);
            }
        }
        public void Close()
        {
            try
            {
                // _explicitlyClosed = true;

                // let the physical close time out if necessary
                _connection.Close(_closeTimeout);
            }
            catch (AlreadyClosedException)
            {
                // Ignore
            }
            catch (Exception e)
            {
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(e);
            }
        }
        public override void OnMessageBatch(List <Message> messages, IModel channel)
        {
            IMessage converted;

            if (ConverterAdapter.IsAmqpMessageList)
            {
                converted = new GenericMessage(messages);
            }
            else
            {
                var messagingMessages = new List <IMessage>();
                foreach (var message in messages)
                {
                    messagingMessages.Add(ToMessagingMessage(message));
                }

                if (ConverterAdapter.IsMessageList)
                {
                    converted = new GenericMessage(messagingMessages);
                }
                else
                {
                    var payloads = new List <object>();
                    foreach (var message in messagingMessages)
                    {
                        payloads.Add(message.Payload);
                    }

                    converted = new GenericMessage(payloads);
                }
            }

            try
            {
                InvokeHandlerAndProcessResult(null, channel, converted);
            }
            catch (Exception e)
            {
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(e);
            }
        }
            public void Acknowledge(Status status)
            {
                // logger.trace("acknowledge(" + status + ") for " + this);
                try
                {
                    var deliveryTag = AckInfo.Response.DeliveryTag;
                    switch (status)
                    {
                    case Status.ACCEPT:
                        AckInfo.Channel.BasicAck(deliveryTag, false);
                        break;

                    case Status.REJECT:
                        AckInfo.Channel.BasicReject(deliveryTag, false);
                        break;

                    case Status.REQUEUE:
                        AckInfo.Channel.BasicReject(deliveryTag, true);
                        break;

                    default:
                        break;
                    }

                    if (AckInfo.Transacted)
                    {
                        AckInfo.Channel.TxCommit();
                    }
                }
                catch (Exception e)
                {
                    throw RabbitExceptionTranslator.ConvertRabbitAccessException(e);
                }
                finally
                {
                    RabbitUtils.CloseChannel(AckInfo.Channel);
                    RabbitUtils.CloseConnection(AckInfo.Connection);
                    IsAcknowledged = true;
                }
            }
        public RC.IModel CreateChannel(bool transactional = false)
        {
            try
            {
                var result = _connection.CreateModel();
                if (result == null)
                {
                    throw new RabbitResourceNotAvailableException("The channelMax limit is reached. Try later.");
                }

                if (transactional)
                {
                    result.TxSelect();
                }

                return(result);
            }
            catch (Exception e)
            {
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(e);
            }
        }
        public void RollbackOnExceptionIfNecessary(Exception ex)
        {
            bool ackRequired = !AcknowledgeMode.IsAutoAck() && (!AcknowledgeMode.IsManual() || ContainerUtils.IsRejectManual(ex));

            try
            {
                if (Transactional)
                {
                    Logger?.LogDebug(ex, "Initiating transaction rollback on application exception");
                    RabbitUtils.RollbackIfNecessary(Channel);
                }

                if (ackRequired)
                {
                    if (DeliveryTags.Count > 0)
                    {
                        ulong deliveryTag = DeliveryTags.Max();
                        Channel.BasicNack(deliveryTag, true, ContainerUtils.ShouldRequeue(DefaultRequeueRejected, ex, Logger));
                    }

                    if (Transactional)
                    {
                        // Need to commit the reject (=nack)
                        RabbitUtils.CommitIfNecessary(Channel);
                    }
                }
            }
            catch (Exception e)
            {
                Logger?.LogError(ex, "Application exception overridden by rollback exception");
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(e); // NOSONAR stack trace loss
            }
            finally
            {
                DeliveryTags.Clear();
            }
        }
        protected virtual IConnection CreateBareConnection()
        {
            try
            {
                var connectionName = ObtainNewConnectionName();

                var rabbitConnection = Connect(connectionName);

                var connection = new SimpleConnection(rabbitConnection, CloseTimeout, _loggerFactory?.CreateLogger <SimpleConnection>());

                _logger?.LogInformation("Created new connection: {connectionName}/{connection}", connectionName, connection);

                if (rabbitConnection != null && RecoveryListener != null)
                {
                    rabbitConnection.RecoverySucceeded       += RecoveryListener.HandleRecoverySucceeded;
                    rabbitConnection.ConnectionRecoveryError += RecoveryListener.HandleConnectionRecoveryError;
                }

                if (rabbitConnection != null && BlockedListener != null)
                {
                    rabbitConnection.ConnectionBlocked   += BlockedListener.HandleBlocked;
                    rabbitConnection.ConnectionUnblocked += BlockedListener.HandleUnblocked;
                }

                if (rabbitConnection != null)
                {
                    rabbitConnection.ConnectionShutdown += ConnectionShutdownCompleted;
                }

                return(connection);
            }
            catch (Exception e)
            {
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(e);
            }
        }
        private void HandleDeclarationException(int passiveDeclareRetries, DeclarationException e)
        {
            if (passiveDeclareRetries > 0 && Channel.IsOpen)
            {
                Logger?.LogWarning(e, "Queue declaration failed; retries left={retries}", passiveDeclareRetries);
                try
                {
                    Thread.Sleep(FailedDeclarationRetryInterval);
                }
                catch (Exception e1)
                {
                    Declaring = false;
                    ActiveObjectCounter.Release(this);
                    throw RabbitExceptionTranslator.ConvertRabbitAccessException(e1);
                }
            }
            else if (e.FailedQueues.Count < Queues.Count)
            {
                Logger?.LogWarning("Not all queues are available; only listening on those that are - configured: {queues}; not available: {notavail}", string.Join(',', Queues), string.Join(',', e.FailedQueues));
                lock (MissingQueues)
                {
                    foreach (var q in e.FailedQueues)
                    {
                        MissingQueues.Add(q);
                    }
                }

                LastRetryDeclaration = DateTimeOffset.Now.ToUnixTimeMilliseconds();
            }
            else
            {
                Declaring = false;
                ActiveObjectCounter.Release(this);
                throw new QueuesNotAvailableException("Cannot prepare queue for listener. Either the queue doesn't exist or the broker will not allow us to use it.", e);
            }
        }
Beispiel #18
0
 protected virtual Exception ConvertRabbitAccessException(Exception ex)
 {
     return(RabbitExceptionTranslator.ConvertRabbitAccessException(ex));
 }
        private static RabbitResourceHolder DoGetTransactionalResourceHolder(IConnectionFactory connectionFactory, IResourceFactory resourceFactory)
        {
            if (connectionFactory == null)
            {
                throw new ArgumentNullException(nameof(connectionFactory));
            }

            if (resourceFactory == null)
            {
                throw new ArgumentNullException(nameof(resourceFactory));
            }

            var resourceHolder = (RabbitResourceHolder)TransactionSynchronizationManager.GetResource(connectionFactory);

            if (resourceHolder != null)
            {
                var model = resourceFactory.GetChannel(resourceHolder);
                if (model != null)
                {
                    return(resourceHolder);
                }
            }

            var resourceHolderToUse = resourceHolder;

            if (resourceHolderToUse == null)
            {
                resourceHolderToUse = new RabbitResourceHolder();
            }

            var    connection = resourceFactory.GetConnection(resourceHolderToUse);
            IModel channel;

            try
            {
                /*
                 * If we are in a listener container, first see if there's a channel registered
                 * for this consumer and the consumer is using the same connection factory.
                 */
                channel = ConsumerChannelRegistry.GetConsumerChannel(connectionFactory);
                if (channel == null && connection == null)
                {
                    connection = resourceFactory.CreateConnection2();
                    if (resourceHolder == null)
                    {
                        /*
                         * While creating a connection, a connection listener might have created a
                         * transactional channel and bound it to the transaction.
                         */
                        resourceHolder = (RabbitResourceHolder)TransactionSynchronizationManager.GetResource(connectionFactory);
                        if (resourceHolder != null)
                        {
                            channel             = resourceHolder.GetChannel();
                            resourceHolderToUse = resourceHolder;
                        }
                    }

                    resourceHolderToUse.AddConnection(connection);
                }

                if (channel == null)
                {
                    channel = resourceFactory.CreateChannel(connection);
                }

                resourceHolderToUse.AddChannel(channel, connection);

                if (!resourceHolderToUse.Equals(resourceHolder))
                {
                    BindResourceToTransaction(resourceHolderToUse, connectionFactory, resourceFactory.IsSynchedLocalTransactionAllowed);
                }

                return(resourceHolderToUse);
            }
            catch (Exception ex)
            {
                RabbitUtils.CloseConnection(connection);
                throw RabbitExceptionTranslator.ConvertRabbitAccessException(ex);
            }
        }
        private void CheckMissingQueues()
        {
            var now = DateTimeOffset.Now.ToUnixTimeMilliseconds();

            if (now - RetryDeclarationInterval > LastRetryDeclaration)
            {
                lock (MissingQueues)
                {
                    List <string> toRemove = new List <string>();
                    Exception     error    = null;
                    foreach (var queueToCheck in MissingQueues)
                    {
                        bool        available       = true;
                        IConnection connection      = null;
                        RC.IModel   channelForCheck = null;
                        try
                        {
                            channelForCheck = ConnectionFactory.CreateConnection().CreateChannel(false);
                            channelForCheck.QueueDeclarePassive(queueToCheck);
                            Logger?.LogInformation("Queue '{queue}' is now available", queueToCheck);
                        }
                        catch (Exception e)
                        {
                            available = false;
                            Logger?.LogWarning(e, "Queue '{queue}' is not available", queueToCheck);
                        }
                        finally
                        {
                            RabbitUtils.CloseChannel(channelForCheck);
                            RabbitUtils.CloseConnection(connection);
                        }

                        if (available)
                        {
                            try
                            {
                                ConsumeFromQueue(queueToCheck);
                                toRemove.Add(queueToCheck);
                            }
                            catch (Exception e)
                            {
                                error = e;
                                break;
                            }
                        }
                    }

                    if (toRemove.Count > 0)
                    {
                        foreach (var remove in toRemove)
                        {
                            MissingQueues.Remove(remove);
                        }
                    }

                    if (error != null)
                    {
                        throw RabbitExceptionTranslator.ConvertRabbitAccessException(error);
                    }
                }

                LastRetryDeclaration = now;
            }
        }