Ejemplo n.º 1
0
        private void DoAck(ConsumerExecutionContext context, AckStrategy ackStrategy)
        {
            const string failedToAckMessage =
                "Basic ack failed because channel was closed with message '{0}'." +
                " Message remains on RabbitMQ and will be retried." +
                " ConsumerTag: {1}, DeliveryTag: {2}";

            var ackResult  = AckResult.Exception;
            var deliverTag = context.Info.DeliverTag;

            try
            {
                ackResult = ackStrategy(context.Consumer.Model, deliverTag);
            }
            catch (AlreadyClosedException alreadyClosedException)
            {
                Logger.Info(failedToAckMessage, alreadyClosedException.Message, context.Info.ConsumerTag, deliverTag);
            }
            catch (IOException ioException)
            {
                Logger.Info(failedToAckMessage, ioException.Message, context.Info.ConsumerTag, deliverTag);
            }
            catch (Exception exception)
            {
                Logger.Error("Unexpected exception when attempting to ACK or NACK\n{0}", exception);
            }
            finally
            {
                EventBus.Publish(new AckEvent(context.Info, context.Properties, context.Body, ackResult));
            }
        }
Ejemplo n.º 2
0
        public void InvokeUserMessageHandler(ConsumerExecutionContext context)
        {
            Logger.Debug("Received \n\tRoutingKey: '{0}'\n\tCorrelationId: '{1}'\n\tConsumerTag: '{2}'" +
                         "\n\tDeliveryTag: {3}\n\tRedelivered: {4}",
                         context.Info.RoutingKey,
                         context.Properties.CorrelationId,
                         context.Info.ConsumerTag,
                         context.Info.DeliverTag,
                         context.Info.Redelivered);

            Task completionTask;

            try
            {
                completionTask = context.UserHandler(context.Body, context.Properties, context.Info);
            }
            catch (Exception exception)
            {
                completionTask = TaskHelpers.FromException(exception);
            }

            if (completionTask.Status == TaskStatus.Created)
            {
                Logger.Error("Task returned from consumer callback is not started. ConsumerTag: '{0}'",
                             context.Info.ConsumerTag);
                return;
            }

            completionTask.ContinueWith(task => DoAck(context, GetAckStrategy(context, task)));
        }
Ejemplo n.º 3
0
        private byte[] CreateErrorMessage(ConsumerExecutionContext context, Exception exception)
        {
            var messageAsString = Encoding.UTF8.GetString(context.Body);
            var error           = new ErrorMessage
            {
                RoutingKey = context.Info.RoutingKey,
                Exchange   = context.Info.Exchange,
                Exception  = exception.ToString(),
                Message    = messageAsString,
                DateTime   = DateTime.UtcNow
            };

            if (context.Properties.Headers == null)
            {
                error.BasicProperties = context.Properties;
            }
            else
            {
                // we'll need to clone context.Properties as we are mutating the headers dictionary
                error.BasicProperties = (MessageProperties)context.Properties.Clone();

                // the RabbitMQClient implictly converts strings to byte[] on sending, but reads them back as byte[]
                // we're making the assumption here that any byte[] values in the headers are strings
                // and all others are basic types. RabbitMq client generally throws a nasty exception if you try
                // to store anything other than basic types in headers anyway.
                //see http://hg.rabbitmq.com/rabbitmq-dotnet-client/file/tip/projects/client/RabbitMQ.Client/src/client/impl/WireFormatting.cs

                error.BasicProperties.Headers = context.Properties.Headers.ToDictionary(
                    kvp => kvp.Key,
                    kvp => kvp.Value is byte[] ? Encoding.UTF8.GetString((byte[])kvp.Value) : kvp.Value);
            }

            return(serializer.Serialize <byte[]>(error));
        }
Ejemplo n.º 4
0
        private string BuildErrorMessage(ConsumerExecutionContext context, Exception exception)
        {
            var message = Encoding.UTF8.GetString(context.Body);

            return("Exception thrown by subscription callback.\n" +
                   string.Format("\tExchange:    '{0}'\n", context.Info.Exchange) +
                   string.Format("\tRouting Key: '{0}'\n", context.Info.RoutingKey) +
                   string.Format("\tRedelivered: '{0}'\n", context.Info.Redelivered) +
                   string.Format("Message:\n{0}\n", message) +
                   string.Format("BasicProperties:\n{0}\n", context.Properties) +
                   string.Format("Exception:\n{0}\n", exception));
        }
Ejemplo n.º 5
0
        private string DeclareErrorExchangeAndBindToDefaultErrorQueue(IModel model, ConsumerExecutionContext context)
        {
            var originalRoutingKey = context.Info.RoutingKey;

            return(errorExchanges.GetOrAdd(originalRoutingKey, _ =>
            {
                var exchangeName = Conventions.ErrorExchangeNamingConvention(context.Info);
                model.ExchangeDeclare(exchangeName, ExchangeType.Direct, durable: true);
                model.QueueBind(Conventions.ErrorQueueNamingConvention(), exchangeName, originalRoutingKey);
                return exchangeName;
            }));
        }
Ejemplo n.º 6
0
        public virtual AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception)
        {
            if (disposed || disposing)
            {
                Logger.Error(
                    "EasyNetQ Consumer Error Handler: DefaultConsumerErrorStrategy was already disposed, when attempting to handle consumer error.  This can occur when messaging is being shut down through disposal of the IBus.  Message will not be ackd to RabbitMQ server and will remain on the RabbitMQ queue.  Error message will not be published to error queue.\n" +
                    "ConsumerTag: {0}, DeliveryTag: {1}\n",
                    context.Info.ConsumerTag,
                    context.Info.DeliverTag);
                return(AckStrategies.NackWithRequeue);
            }

            try
            {
                Connect();

                using (var model = connection.CreateModel())
                {
                    var errorExchange = DeclareErrorExchangeQueueStructure(model, context);

                    var messageBody = CreateErrorMessage(context, exception);
                    var properties  = model.CreateBasicProperties();
                    properties.Persistent = true;
                    properties.Type       = typeNameSerializer.Serialize(typeof(ErrorMessage));

                    model.BasicPublish(errorExchange, context.Info.RoutingKey, properties, messageBody);
                }
            }
            catch (BrokerUnreachableException)
            {
                // thrown if the broker is unreachable during initial creation.
                Logger.Error("EasyNetQ Consumer Error Handler cannot connect to Broker\n" +
                             CreateConnectionCheckMessage());
            }
            catch (OperationInterruptedException interruptedException)
            {
                // thrown if the broker connection is broken during declare or publish.
                Logger.Error("EasyNetQ Consumer Error Handler: Broker connection was closed while attempting to publish Error message.\n" +
                             string.Format("Exception was: '{0}'\n", interruptedException.Message) +
                             CreateConnectionCheckMessage());
            }
            catch (Exception unexpectedException)
            {
                // Something else unexpected has gone wrong :(
                Logger.Error("EasyNetQ Consumer Error Handler: Failed to publish error message\nException is:\n"
                             + unexpectedException);
            }
            return(AckStrategies.Ack);
        }
Ejemplo n.º 7
0
        private AckStrategy GetAckStrategy(ConsumerExecutionContext context, Task task)
        {
            var ackStrategy = AckStrategies.Ack;

            try
            {
                if (task.IsFaulted)
                {
                    Logger.Error(BuildErrorMessage(context, task.Exception));
                    ackStrategy = consumerErrorStrategy.HandleConsumerError(context, task.Exception);
                }
                else if (task.IsCanceled)
                {
                    ackStrategy = consumerErrorStrategy.HandleConsumerCancelled(context);
                }
            }
            catch (Exception consumerErrorStrategyError)
            {
                Logger.Error("Exception in ConsumerErrorStrategy:\n{0}", consumerErrorStrategyError);
                return(AckStrategies.Nothing);
            }
            return(ackStrategy);
        }
Ejemplo n.º 8
0
        public void HandleBasicDeliver(
            string consumerTag,
            ulong deliveryTag,
            bool redelivered,
            string exchange,
            string routingKey,
            IBasicProperties properties,
            byte[] body)
        {
            Logger.Debug("HandleBasicDeliver on consumer: {0}, deliveryTag: {1}", consumerTag, deliveryTag);

            if (disposed)
            {
                // this message's consumer has stopped, so just return
                Logger.Info("Consumer has stopped running. Consumer '{0}' on queue '{1}'. Ignoring message",
                            ConsumerTag, queue.Name);
                return;
            }

            if (onMessage == null)
            {
                Logger.Error("User consumer callback, 'onMessage' has not been set for consumer '{0}'." +
                             "Please call InternalConsumer.StartConsuming before passing the consumer to basic.consume",
                             ConsumerTag);
                return;
            }

            var messageReceivedInfo = new MessageReceivedInfo(consumerTag, deliveryTag, redelivered, exchange, routingKey, queue.Name);
            var messsageProperties  = new MessageProperties(properties);
            var context             = new ConsumerExecutionContext(onMessage, messageReceivedInfo, messsageProperties, body, this);

            consumerDispatcher.QueueAction(() =>
            {
                EventBus.Publish(new DeliveredMessageEvent(messageReceivedInfo, messsageProperties, body));
                handlerRunner.InvokeUserMessageHandler(context);
            });
        }
Ejemplo n.º 9
0
 public AckStrategy HandleConsumerCancelled(ConsumerExecutionContext context)
 {
     return(AckStrategies.Ack);
 }
Ejemplo n.º 10
0
 private string DeclareErrorExchangeQueueStructure(IModel model, ConsumerExecutionContext context)
 {
     DeclareDefaultErrorQueue(model);
     return(DeclareErrorExchangeAndBindToDefaultErrorQueue(model, context));
 }