Ejemplo n.º 1
0
        public Result CreateQueue(string queueName, string exchangeToBind, string bindRoutingKey)
        {
            var res = new Result();

            try
            {
                using (var connection = GetConnection(ServiceDescription + "_UtilService"))
                    using (var channel = connection.CreateModel())
                    {
                        RabbitMqUtilities.CreateQueueOrGetInfo(queueName, channel);

                        var key      = string.IsNullOrWhiteSpace(bindRoutingKey) ? string.Empty : bindRoutingKey;
                        var exchange = string.IsNullOrWhiteSpace(exchangeToBind) ? string.Empty : exchangeToBind;

                        if (!string.IsNullOrWhiteSpace(exchange))
                        {
                            channel.QueueBind(queueName, exchange, key);
                        }

                        res.Success = true;
                    }
            }
            catch (Exception e)
            {
                res.Success          = false;
                res.ErrorDescription = e.Message;
                res.ErrorCode        = -1;
            }

            return(res);
        }
        /// <summary>
        /// StartConsumers - start consumers and connect them to a queue.
        /// </summary>
        /// <param name="consumerName">Consumer name</param>
        /// <param name="retryQueueDetails">Retry queue details if a message needs to be requeued with a delay (a Dead letter exchange must be defined)</param>
        /// <param name="queueName">Queue where the consumers will connect (optional - if not defined, the config value is used)</param>
        /// <param name="totalConsumers">Total consumers to start (optional - if not defined, the config value is used)</param>
        /// <param name="createQueue">Create queue to connect when starting consumers (optional - default is false)</param>
        /// <exception cref="RabbitMQClientException"></exception>
        public void StartConsumers(string consumerName, RetryQueueDetails retryQueueDetails, string queueName = null, byte?totalConsumers = null, bool createQueue = false)
        {
            var config = (IBrokerConfigConsumers)_config;

            var totalConsumersToStart = totalConsumers ?? config.TotalInstances;

            if (totalConsumersToStart <= 0)
            {
                throw new ArgumentException("Invalid total number of consumers to start");
            }

            var triedCreateQueue = false;

            for (var i = 0; i < totalConsumersToStart; i++)
            {
                var routingKeyOrQueueName =
                    string.IsNullOrWhiteSpace(queueName) ? config.RoutingKeyOrQueueName : queueName;

                var totalCreatedConsumers = _consumers.Count;

                var connection = GetConnection(ServiceDescription + "_" + i, totalCreatedConsumers, MaxChannelsPerConnection);

                var channel = connection.CreateModel();

                if (createQueue && !triedCreateQueue)
                {
                    try
                    {
                        RabbitMqUtilities.CreateQueueOrGetInfo(routingKeyOrQueueName, channel);
                        triedCreateQueue = true;
                    }
                    catch (Exception e)
                    {
                        throw new RabbitMqClientException($"Unable do create queue. Details: {e.Message}", e);
                    }
                }

                var consumer = new AsyncEventingBasicConsumerExtended(channel)
                {
                    ConnectedToPort = connection.Endpoint.Port,
                    ConnectedToHost = connection.Endpoint.HostName,
                    ConnectionTime  = DateTime.Now,
                    Id = i,
                    RetentionPeriodInRetryQueueMilliseconds    = retryQueueDetails?.RetentionPeriodInRetryQueueMilliseconds ?? 0,
                    RetentionPeriodInRetryQueueMillisecondsMax = retryQueueDetails?.RetentionPeriodInRetryQueueMillisecondsMax ?? 0,
                    RetryQueue = retryQueueDetails?.RetryQueue
                };

                consumer.Received += Consumer_Received;
                consumer.Shutdown += Consumer_Shutdown;

                var tag = $"{consumerName}_{i}";

                consumer.ConsumerTag = tag;

                _consumers.Add(consumer);

                channel.BasicConsume(routingKeyOrQueueName, false, tag, consumer);
            }
        }
        private async Task Consumer_Received(object sender, BasicDeliverEventArgs e)
        {
            var consumerTag           = e.ConsumerTag;
            var routingKeyOrQueueName = e.RoutingKey;
            var exchange = e.Exchange;
            var message  = "";

            try
            {
                message = Encoding.UTF8.GetString(e.Body.Span.ToArray());

                var consumer = (AsyncEventingBasicConsumerExtended)sender;

                consumer.LastMessageDate = DateTime.Now;

                var firstErrorTimestamp = RabbitMqUtilities.GetFirstErrorTimeStampFromMessageArgs(e.BasicProperties);
                var additionalInfo      = RabbitMqUtilities.GetAdditionalInfoFromMessageArgs(e.BasicProperties);

                var model = consumer.Model;

                var messageProcessInstruction = await GetMessageProcessInstruction(routingKeyOrQueueName, consumerTag, firstErrorTimestamp, exchange, message, additionalInfo).ConfigureAwait(false);

                switch (messageProcessInstruction.Value)
                {
                case Constants.MessageProcessInstruction.OK:
                    model.BasicAck(e.DeliveryTag, false);
                    break;

                case Constants.MessageProcessInstruction.IgnoreMessage:
                    model.BasicReject(e.DeliveryTag, false);
                    break;

                case Constants.MessageProcessInstruction.IgnoreMessageWithRequeue:
                    model.BasicReject(e.DeliveryTag, true);
                    break;

                case Constants.MessageProcessInstruction.RequeueMessageWithDelay:
                    RequeueMessageWithDelay(consumer, e, messageProcessInstruction.AdditionalInfo);
                    model.BasicReject(e.DeliveryTag, false);
                    break;

                default:
                    model.BasicAck(e.DeliveryTag, false);
                    break;
                }
            }
            catch (Exception ex)
            {
                await OnMessageReceiveError(routingKeyOrQueueName, consumerTag, exchange, message, ex.Message)
                .ConfigureAwait(false);
            }
        }
 protected static void CreateQueue(string routingKeyOrQueueName, bool createQueue, string exchange, IModel channel)
 {
     if (string.IsNullOrWhiteSpace(exchange) && createQueue)
     {
         try
         {
             RabbitMqUtilities.CreateQueueOrGetInfo(routingKeyOrQueueName, channel);
         }
         catch (Exception e)
         {
             throw new RabbitMqClientException($"Unable do create queue. Details: {e.Message}", e);
         }
     }
 }
        private void RequeueMessageWithDelay(AsyncEventingBasicConsumerExtended consumer, BasicDeliverEventArgs deliveryArgs, string messageAdditionalInfo)
        {
            if (string.IsNullOrWhiteSpace(consumer.RetryQueue))
            {
                return;
            }

            var properties = consumer.Model.CreateBasicProperties();

            RabbitMqUtilities.SetPropertiesSenderRequeueMessageWithDelay(properties, consumer.RetentionPeriodInRetryQueueMilliseconds, consumer.RetentionPeriodInRetryQueueMillisecondsMax);

            var firstErrorTimeStamp = RabbitMqUtilities.GetFirstErrorTimeStampFromMessageArgs(deliveryArgs.BasicProperties);

            SetFirstErrorTimeStampToProperties(firstErrorTimeStamp, properties);
            SetMessageAdditionalInfoToProperties(messageAdditionalInfo, properties);

            consumer.Model.BasicPublish(
                "",
                consumer.RetryQueue,
                properties,
                deliveryArgs.Body);
        }
        protected void _Send(string exchangeName, string routingKeyOrQueueName, bool createQueue, IModel channel,
                             string encodingName, IBrokerConfigSender config, byte[] body)
        {
            var properties = channel.CreateBasicProperties();

            RabbitMqUtilities.SetPropertiesSender(properties, encodingName);

            var exchange = GetExchange(exchangeName, config);

            CreateQueue(routingKeyOrQueueName, createQueue, exchange, channel);

            var routingKey = GetRoutingKey(routingKeyOrQueueName, config);

            if (channel.IsClosed)
            {
                throw new Exception("Channel is closed");
            }

            channel.BasicPublish(
                exchange,
                routingKey,
                properties,
                body);
        }