예제 #1
0
        public void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, IBasicProperties properties, byte[] body)
        {
            logger.DebugFormat("Message delivered to consumer {consumerTag} with deliveryTag {deliveryTag}", consumerTag, deliveryTag);

            if (disposed)
            {
                // this message's consumer has stopped, so just return
                logger.InfoFormat(
                    "Consumer with consumerTag {consumerTag} on queue {queue} has stopped running. Ignoring message",
                    ConsumerTag,
                    Queue.Name
                    );

                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);
            });
        }
예제 #2
0
 private async Task <AckStrategy> InvokeUserMessageHandlerInternalAsync(
     ConsumerExecutionContext context, CancellationToken cancellationToken
     )
 {
     try
     {
         try
         {
             return(await context.Handler(
                        context.Body, context.Properties, context.ReceivedInfo, cancellationToken
                        ).ConfigureAwait(false));
         }
         catch (OperationCanceledException)
         {
             return(consumerErrorStrategy.HandleConsumerCancelled(context));
         }
         catch (Exception exception)
         {
             return(consumerErrorStrategy.HandleConsumerError(context, exception));
         }
     }
     catch (Exception exception)
     {
         logger.Error(exception, "Consumer error strategy has failed");
         return(AckStrategies.NackWithRequeue);
     }
 }
        private byte[] CreateErrorMessage(ConsumerExecutionContext context, Exception exception)
        {
            var messageAsString = errorMessageSerializer.Serialize(context.Body);
            var error           = new Error
            {
                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.MessageToBytes(error));
        }
예제 #4
0
        public void InvokeUserMessageHandler(ConsumerExecutionContext context)
        {
            Preconditions.CheckNotNull(context, "context");

            logger.DebugWrite("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.ErrorWrite("Task returned from consumer callback is not started. ConsumerTag: '{0}'",
                                  context.Info.ConsumerTag);
                return;
            }

            completionTask.ContinueWith(task => DoAck(context, GetAckStrategy(context, task)));
        }
예제 #5
0
        public void InvokeUserMessageHandler(ConsumerExecutionContext context)
        {
            Preconditions.CheckNotNull(context, "context");

            logger.DebugWrite("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.ErrorWrite("Task returned from consumer callback is not started. ConsumerTag: '{0}'",
                    context.Info.ConsumerTag);
                return;
            }
            
            completionTask.ContinueWith(task => DoAck(context, GetAckStrategy(context, task)));
        }
        public void SetUp()
        {
            //var logger = new ConsoleLogger();
            var logger = MockRepository.GenerateStub<IEasyNetQLogger>();
            var consumerErrorStrategy = MockRepository.GenerateStub<IConsumerErrorStrategy>();
            var eventBus = new EventBus();

            handlerRunner = new HandlerRunner(logger, consumerErrorStrategy, eventBus);

            Func<byte[], MessageProperties, MessageReceivedInfo, Task> userHandler = (body, properties, info) => 
                Task.Factory.StartNew(() =>
                    {
                        deliveredBody = body;
                        deliveredProperties = properties;
                        deliveredInfo = info;
                    });

            var consumer = MockRepository.GenerateStub<IBasicConsumer>();
            channel = MockRepository.GenerateStub<IModel>();
            consumer.Stub(x => x.Model).Return(channel).Repeat.Any();

            var context = new ConsumerExecutionContext(
                userHandler, messageInfo, messageProperties, messageBody, consumer);

            var autoResetEvent = new AutoResetEvent(false);
            eventBus.Subscribe<AckEvent>(x => autoResetEvent.Set());

            handlerRunner.InvokeUserMessageHandler(context);

            autoResetEvent.WaitOne(1000);
        }
예제 #7
0
        public void HandleBasicDeliver(
            string consumerTag,
            ulong deliveryTag,
            bool redelivered,
            string exchange,
            string routingKey,
            IBasicProperties properties,
            byte[] body)
        {
            logger.DebugWrite("HandleBasicDeliver on consumer: {0}, deliveryTag: {1}", consumerTag, deliveryTag);

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

            if (onMessage == null)
            {
                logger.ErrorWrite("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(() => handlerRunner.InvokeUserMessageHandler(context));
        }
예제 #8
0
        private async Task <AckStrategy> InvokeUserMessageHandlerInternalAsync(ConsumerExecutionContext context)
        {
            try
            {
                try
                {
                    await context.UserHandler(context.Body, context.Properties, context.Info).ConfigureAwait(false);
                }
                catch (OperationCanceledException)
                {
                    return(consumerErrorStrategy.HandleConsumerCancelled(context));
                }
                catch (Exception exception)
                {
                    logger.Error(
                        exception,
                        "Exception thrown by subscription callback, receivedInfo={receivedInfo}, properties={properties}, message={message}",
                        context.Info,
                        context.Properties,
                        Convert.ToBase64String(context.Body)
                        );
                    return(consumerErrorStrategy.HandleConsumerError(context, exception));
                }
            }
            catch (Exception exception)
            {
                logger.Error(exception, "Consumer error strategy has failed");
                return(AckStrategies.NackWithRequeue);
            }

            return(AckStrategies.Ack);
        }
        public void SetUp()
        {
            postAckCallbackWasRun = false;

            //var logger = new ConsoleLogger();
            var logger = MockRepository.GenerateStub<IEasyNetQLogger>();
            var consumerErrorStrategy = MockRepository.GenerateStub<IConsumerErrorStrategy>();

            handlerRunner = new HandlerRunner(logger, consumerErrorStrategy);

            Func<byte[], MessageProperties, MessageReceivedInfo, Task> userHandler = (body, properties, info) =>
                Task.Factory.StartNew(() =>
                    {
                        deliveredBody = body;
                        deliveredProperties = properties;
                        deliveredInfo = info;
                    });

            var consumer = MockRepository.GenerateStub<IBasicConsumer>();
            channel = MockRepository.GenerateStub<IModel>();
            consumer.Stub(x => x.Model).Return(channel).Repeat.Any();

            var context = new ConsumerExecutionContext(
                userHandler, messageInfo, messageProperties, messageBody, consumer);

            context.SetPostAckCallback(() => postAckCallbackWasRun = true);

            var autoResetEvent = new AutoResetEvent(false);
            ((HandlerRunner) handlerRunner).SynchronisationAction = () => autoResetEvent.Set();

            handlerRunner.InvokeUserMessageHandler(context);

            autoResetEvent.WaitOne(1000);
        }
예제 #10
0
        protected virtual AckStrategy GetAckStrategy(ConsumerExecutionContext context, Task task)
        {
            try
            {
                if (task.IsFaulted)
                {
                    logger.Error(
                        task.Exception,
                        "Exception thrown by subscription callback, receivedInfo={receivedInfo}, properties={properties}, message={message}",
                        context.Info,
                        context.Properties,
                        Convert.ToBase64String(context.Body)
                        );
                    return(consumerErrorStrategy.HandleConsumerError(context, task.Exception));
                }

                if (task.IsCanceled)
                {
                    return(consumerErrorStrategy.HandleConsumerCancelled(context));
                }

                return(AckStrategies.Ack);
            }
            catch (Exception exception)
            {
                logger.Error(exception, "Consumer error strategy has failed");
                return(AckStrategies.NackWithRequeue);
            }
        }
예제 #11
0
        public virtual AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception)
        {
            Preconditions.CheckNotNull(context, "context");
            Preconditions.CheckNotNull(exception, "exception");

            if (disposed || disposing)
            {
                logger.ErrorFormat(
                    "ErrorStrategy was already disposed, when attempting to handle consumer error. Error message will not be published and message with receivedInfo={receivedInfo} will be requeed",
                    context.Info
                    );

                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(Error));

                    model.BasicPublish(errorExchange, context.Info.RoutingKey, properties, messageBody);

                    return(AckStrategies.Ack);
                }
            }
            catch (BrokerUnreachableException unreachableException)
            {
                // thrown if the broker is unreachable duringe initial creation.
                logger.Error(
                    unreachableException,
                    "Cannot connect to broker while attempting to publish error message"
                    );
            }
            catch (OperationInterruptedException interruptedException)
            {
                // thrown if the broker connection is broken during declare or publish.
                logger.Error(
                    interruptedException,
                    "Broker connection was closed while attempting to publish error message"
                    );
            }
            catch (Exception unexpectedException)
            {
                // Something else unexpected has gone wrong :(
                logger.Error(unexpectedException, "Failed to publish error message");
            }

            return(AckStrategies.NackWithRequeue);
        }
예제 #12
0
        private void AckOrNackSent(ConsumerExecutionContext context)
        {
            var ackOrNackWasSent = AckOrNackWasSent;

            if (ackOrNackWasSent != null)
            {
                ackOrNackWasSent(context);
            }
        }
예제 #13
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));
        }
예제 #14
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);
        }
        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;
            });
        }
예제 #16
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;
            }));
        }
        public virtual AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception)
        {
            Preconditions.CheckNotNull(context, "context");
            Preconditions.CheckNotNull(exception, "exception");

            if (disposed || disposing)
            {
                logger.ErrorWrite(
                    "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 (Error));

                    model.BasicPublish(errorExchange, context.Info.RoutingKey, properties, messageBody);
                }
            }
            catch (BrokerUnreachableException)
            {
                // thrown if the broker is unreachable during initial creation.
                logger.ErrorWrite("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.ErrorWrite("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.ErrorWrite("EasyNetQ Consumer Error Handler: Failed to publish error message\nException is:\n"
                    + unexpectedException);
            }
            return AckStrategies.Ack;
        }
        public virtual AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception)
        {
            Preconditions.CheckNotNull(context, "context");
            Preconditions.CheckNotNull(exception, "exception");

            if (disposed || disposing)
            {
                logger.ErrorWrite(
                    "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(Error));

                    model.BasicPublish(errorExchange, context.Info.RoutingKey, properties, messageBody);
                }
            }
            catch (BrokerUnreachableException)
            {
                // thrown if the broker is unreachable during initial creation.
                logger.ErrorWrite("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.ErrorWrite("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.ErrorWrite("EasyNetQ Consumer Error Handler: Failed to publish error message\nException is:\n"
                                  + unexpectedException);
            }
            return(AckStrategies.Ack);
        }
예제 #19
0
        private void DoAck(ConsumerExecutionContext context, Action <IModel, ulong> 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}";

            try
            {
                Preconditions.CheckNotNull(context.Consumer.Model, "context.Consumer.Model");

                ackStrategy(context.Consumer.Model, context.Info.DeliverTag);
            }
            catch (AlreadyClosedException alreadyClosedException)
            {
                logger.InfoWrite(failedToAckMessage,
                                 alreadyClosedException.Message,
                                 context.Info.ConsumerTag,
                                 context.Info.DeliverTag);
            }
            catch (IOException ioException)
            {
                logger.InfoWrite(failedToAckMessage,
                                 ioException.Message,
                                 context.Info.ConsumerTag,
                                 context.Info.DeliverTag);
            }
            catch (Exception exception)
            {
                logger.ErrorWrite("Unexpected exception when attempting to ACK or NACK\n{0}", exception);
            }
            finally
            {
                try
                {
                    foreach (var postAckCallback in context.PostAckCallbacks)
                    {
                        postAckCallback();
                    }
                }
                catch (Exception exception)
                {
                    logger.ErrorWrite("Exception in PostAckCallback:\n{0}", exception);
                }

                if (SynchronisationAction != null)
                {
                    SynchronisationAction();
                }
            }
        }
예제 #20
0
 private void HandleErrorInSubscriptionHandler(ConsumerExecutionContext context,
                                               Exception exception)
 {
     logger.ErrorWrite(BuildErrorMessage(context, exception));
     try
     {
         var strategy = consumerErrorStrategy.HandleConsumerError(context, exception);
         DoAck(context, (model, deliveryTag) => ExceptionAckStrategy(model, deliveryTag, strategy));
     }
     catch (Exception consumerErrorStrategyError)
     {
         logger.ErrorWrite("Exception in ConsumerErrorStrategy:\n{0}",
                           consumerErrorStrategyError);
     }
 }
예제 #21
0
        private byte[] CreateErrorMessage(ConsumerExecutionContext context, Exception exception)
        {
            var messageAsString = Encoding.UTF8.GetString(context.Body);
            var error           = new Error
            {
                RoutingKey      = context.Info.RoutingKey,
                Exchange        = context.Info.Exchange,
                Exception       = exception.ToString(),
                Message         = messageAsString,
                DateTime        = DateTime.Now,
                BasicProperties = context.Properties
            };

            return(serializer.MessageToBytes(error));
        }
예제 #22
0
        private string DeclareErrorExchangeWithQueue(IModel model, ConsumerExecutionContext context)
        {
            var errorExchangeName = conventions.ErrorExchangeNamingConvention(context.Info);
            var errorQueueName    = conventions.ErrorQueueNamingConvention(context.Info);
            var routingKey        = context.Info.RoutingKey;

            var errorTopologyIdentifier = $"{errorExchangeName}-{errorQueueName}-{routingKey}";

            existingErrorExchangesWithQueues.GetOrAdd(errorTopologyIdentifier, _ =>
            {
                DeclareAndBindErrorExchangeWithErrorQueue(model, errorExchangeName, errorQueueName, routingKey);
                return(null);
            });

            return(errorExchangeName);
        }
        public void Should_handle_an_exception_by_writing_to_the_error_queue()
        {
            const string originalMessage = "{ Text:\"Hello World\"}";
            var originalMessageBody = Encoding.UTF8.GetBytes(originalMessage);

            var exception = new Exception("I just threw!");

            var context = new ConsumerExecutionContext(
                (bytes, properties, arg3) => null,
                new MessageReceivedInfo("consumertag", 0, false, "orginalExchange", "originalRoutingKey", "queue"),
                new MessageProperties
                {
                    CorrelationId = "123",
                    AppId = "456"
                },
                originalMessageBody,
                MockRepository.GenerateStub<IBasicConsumer>()
                );

            consumerErrorStrategy.HandleConsumerError(context, exception);

            Thread.Sleep(100);

            // Now get the error message off the error queue and assert its properties
            using(var connection = connectionFactory.CreateConnection())
            using(var model = connection.CreateModel())
            {
                var getArgs = model.BasicGet(conventions.ErrorQueueNamingConvention(), true);
                if (getArgs == null)
                {
                    Assert.Fail("Nothing on the error queue");
                }
                else
                {
                    var message = serializer.BytesToMessage<Error>(getArgs.Body);

                    message.RoutingKey.ShouldEqual(context.Info.RoutingKey);
                    message.Exchange.ShouldEqual(context.Info.Exchange);
                    message.Message.ShouldEqual(originalMessage);
                    message.Exception.ShouldEqual("System.Exception: I just threw!");
                    message.DateTime.Date.ShouldEqual(DateTime.Now.Date);
                    message.BasicProperties.CorrelationId.ShouldEqual(context.Properties.CorrelationId);
                    message.BasicProperties.AppId.ShouldEqual(context.Properties.AppId);
                }
            }
        }
예제 #24
0
        /// <inheritdoc />
        public void HandleBasicDeliver(
            string consumerTag,
            ulong deliveryTag,
            bool redelivered,
            string exchange,
            string routingKey,
            IBasicProperties properties,
            ReadOnlyMemory <byte> body
            )
        {
            if (logger.IsDebugEnabled())
            {
                logger.DebugFormat("Message delivered to consumer {consumerTag} with deliveryTag {deliveryTag}", consumerTag, deliveryTag);
            }

            if (disposed)
            {
                // this message's consumer has stopped, so just return
                logger.InfoFormat(
                    "Consumer with consumerTag {consumerTag} on queue {queue} has stopped running. Ignoring message",
                    ConsumerTag,
                    Queue.Name
                    );

                return;
            }

            var bodyBytes           = body.ToArray();
            var messageReceivedInfo = new MessageReceivedInfo(consumerTag, deliveryTag, redelivered, exchange, routingKey, Queue.Name);
            var messageProperties   = new MessageProperties(properties);
            var context             = new ConsumerExecutionContext(OnMessage, messageReceivedInfo, messageProperties, bodyBytes);

            eventBus.Publish(new DeliveredMessageEvent(messageReceivedInfo, messageProperties, bodyBytes));
            handlerRunner.InvokeUserMessageHandlerAsync(context)
            .ContinueWith(async x =>
            {
                var ackStrategy = await x.ConfigureAwait(false);
                consumerDispatcher.QueueAction(() =>
                {
                    var ackResult = ackStrategy(Model, deliveryTag);
                    eventBus.Publish(new AckEvent(messageReceivedInfo, messageProperties, bodyBytes, ackResult));
                });
            },
                          TaskContinuationOptions.ExecuteSynchronously
                          );
        }
예제 #25
0
        /// <inheritdoc />
        public virtual async Task <AckStrategy> InvokeUserMessageHandlerAsync(
            ConsumerExecutionContext context, CancellationToken cancellationToken
            )
        {
            if (logger.IsDebugEnabled())
            {
                logger.DebugFormat("Received message with receivedInfo={receivedInfo}", context.ReceivedInfo);
            }

            var ackStrategy = await InvokeUserMessageHandlerInternalAsync(context, cancellationToken).ConfigureAwait(false);

            return((model, tag) =>
            {
                try
                {
                    return ackStrategy(model, tag);
                }
                catch (AlreadyClosedException alreadyClosedException)
                {
                    logger.Info(
                        alreadyClosedException,
                        "Failed to ACK or NACK, message will be retried, receivedInfo={receivedInfo}",
                        context.ReceivedInfo
                        );
                }
                catch (IOException ioException)
                {
                    logger.Info(
                        ioException,
                        "Failed to ACK or NACK, message will be retried, receivedInfo={receivedInfo}",
                        context.ReceivedInfo
                        );
                }
                catch (Exception exception)
                {
                    logger.Error(
                        exception,
                        "Unexpected exception when attempting to ACK or NACK, receivedInfo={receivedInfo}",
                        context.ReceivedInfo
                        );
                }

                return AckResult.Exception;
            });
        }
예제 #26
0
        public virtual void InvokeUserMessageHandler(ConsumerExecutionContext context)
        {
            Preconditions.CheckNotNull(context, "context");

            logger.DebugFormat("Received message with receivedInfo={receivedInfo}", context.Info);

            Task completionTask;

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

            completionTask.ContinueWith(task => DoAck(context, GetAckStrategy(context, task)));
        }
예제 #27
0
        public void InvokeUserMessageHandler(ConsumerExecutionContext context)
        {
            Preconditions.CheckNotNull(context, "context");

            logger.DebugWrite("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);

            try
            {
                var completionTask = context.UserHandler(context.Body, context.Properties, context.Info);

                if (completionTask.Status == TaskStatus.Created)
                {
                    logger.ErrorWrite("Task returned from consumer callback is not started. ConsumerTag: '{0}'",
                        context.Info.ConsumerTag);
                }
                else
                {
                    completionTask.ContinueWith(task =>
                    {
                        if (task.IsFaulted)
                        {
                            var exception = task.Exception;
                            HandleErrorInSubscriptionHandler(context, exception);
                        }
                        else
                        {
                            DoAck(context, SuccessAckStrategy);
                        }
                    });
                }
            }
            catch (Exception exception)
            {
                HandleErrorInSubscriptionHandler(context, exception);
            }
        }
예제 #28
0
        public virtual PostExceptionAckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception)
        {
            Preconditions.CheckNotNull(context, "context");
            Preconditions.CheckNotNull(exception, "exception");

            try
            {
                Connect();

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

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

                    model.BasicPublish(errorExchange, context.Info.RoutingKey, properties, messageBody);
                }
            }
            catch (BrokerUnreachableException)
            {
                // thrown if the broker is unreachable during initial creation.
                logger.ErrorWrite("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.ErrorWrite("EasyNetQ Consumer Error Handler: Broker connection was closed while attempting to publish Error message.\n" +
                                  string.Format("Message was: '{0}'\n", interruptedException.Message) +
                                  CreateConnectionCheckMessage());
            }
            catch (Exception unexpectedException)
            {
                // Something else unexpected has gone wrong :(
                logger.ErrorWrite("EasyNetQ Consumer Error Handler: Failed to publish error message\nException is:\n"
                                  + unexpectedException);
            }
            return(Consumer.PostExceptionAckStrategy.ShouldAck);
        }
예제 #29
0
        public virtual void HandleConsumerError(ConsumerExecutionContext context, Exception exception)
        {
            // Preconditions.CheckNotNull(context, "context");
            // Preconditions.CheckNotNull(exception, "exception");

            try
            {
                Connect();

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

                    var messageBody = CreateErrorMessage(context, exception);
                    var properties = model.CreateBasicProperties();
                    properties.SetPersistent(true);
                    properties.Type = TypeNameSerializer.Serialize(typeof(Error));

                    model.BasicPublish(errorExchange, context.Info.RoutingKey, properties, messageBody);
                }
            }
            catch (BrokerUnreachableException)
            {
                // thrown if the broker is unreachable during initial creation.
                logger.ErrorWrite("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.ErrorWrite(
                    "EasyNetQ Consumer Error Handler: Broker connection was closed while attempting to publish Error message.\n" +
                    string.Format("Message was: '{0}'\n", interruptedException.Message) +
                    CreateConnectionCheckMessage());
            }
            catch (Exception unexpecctedException)
            {
                // Something else unexpected has gone wrong :(
                logger.ErrorWrite("EasyNetQ Consumer Error Handler: Failed to publish error message\nException is:\n"
                                  + unexpecctedException);
            }
        }
예제 #30
0
        public void InvokeUserMessageHandler(ConsumerExecutionContext context)
        {
            Preconditions.CheckNotNull(context, "context");

            logger.DebugWrite("Recieved \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);

            try
            {
                var completionTask = context.UserHandler(context.Body, context.Properties, context.Info);

                if (completionTask.Status == TaskStatus.Created)
                {
                    logger.ErrorWrite("Task returned from consumer callback is not started. ConsumerTag: '{0}'",
                                      context.Info.ConsumerTag);
                }
                else
                {
                    completionTask.ContinueWith(task =>
                    {
                        if (task.IsFaulted)
                        {
                            var exception = task.Exception;
                            HandleErrorInSubscriptionHandler(context, exception);
                        }
                        else
                        {
                            DoAck(context, SuccessAckStrategy);
                        }
                    });
                }
            }
            catch (Exception exception)
            {
                HandleErrorInSubscriptionHandler(context, exception);
            }
        }
예제 #31
0
        private string BuildErrorMessage(ConsumerExecutionContext context, Exception exception)
        {
            var message = Encoding.UTF8.GetString(context.Body);

            var properties        = context.Properties;
            var propertiesMessage = new StringBuilder();

            if (properties != null)
            {
                properties.AppendPropertyDebugStringTo(propertiesMessage);
            }

            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", propertiesMessage) +
                   string.Format("Exception:\n{0}\n", exception));
        }
예제 #32
0
        protected virtual void DoAck(ConsumerExecutionContext context, AckStrategy ackStrategy)
        {
            var ackResult = AckResult.Exception;

            try
            {
                Preconditions.CheckNotNull(context.Consumer.Model, "context.Consumer.Model");

                ackResult = ackStrategy(context.Consumer.Model, context.Info.DeliverTag);
            }
            catch (AlreadyClosedException alreadyClosedException)
            {
                logger.Info(
                    alreadyClosedException,
                    "Failed to ACK or NACK, message will be retried, receivedInfo={receivedInfo}",
                    context.Info
                    );
            }
            catch (IOException ioException)
            {
                logger.Info(
                    ioException,
                    "Failed to ACK or NACK, message will be retried, receivedInfo={receivedInfo}",
                    context.Info
                    );
            }
            catch (Exception exception)
            {
                logger.Error(
                    exception,
                    "Unexpected exception when attempting to ACK or NACK, receivedInfo={receivedInfo}",
                    context.Info
                    );
            }
            finally
            {
                eventBus.Publish(new AckEvent(context.Info, context.Properties, context.Body, ackResult));
            }
        }
예제 #33
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;

            try
            {
                Preconditions.CheckNotNull(context.Consumer.Model, "context.Consumer.Model");

                ackResult = ackStrategy(context.Consumer.Model, context.Info.DeliverTag);
            }
            catch (AlreadyClosedException alreadyClosedException)
            {
                logger.InfoWrite(failedToAckMessage,
                                 alreadyClosedException.Message,
                                 context.Info.ConsumerTag,
                                 context.Info.DeliverTag);
            }
            catch (IOException ioException)
            {
                logger.InfoWrite(failedToAckMessage,
                                 ioException.Message,
                                 context.Info.ConsumerTag,
                                 context.Info.DeliverTag);
            }
            catch (Exception exception)
            {
                logger.ErrorWrite("Unexpected exception when attempting to ACK or NACK\n{0}", exception);
            }
            finally
            {
                eventBus.Publish(new AckEvent(context.Info, context.Properties, context.Body, ackResult));
            }
        }
        public virtual AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception)
        {
            try
            {
                Connect();

                using (var model = connection.CreateModel())
                {
                    var errorExchange = DeclareErrorExchangeQueueStructure(model, context);
                    var connectionString = ""; //ConfigHelper.ConnectionString;
                    //Get from IoC Container
                    var bus = RabbitHutch.CreateBus(connectionString);
                    var exchange = bus.Advanced.ExchangeDeclare(errorExchange, "direct", passive: true);
                    // Send
                    bus.Advanced.Publish(exchange, errorExchange, false, false, context.Properties, context.Body);
                }
            }
            catch (BrokerUnreachableException)
            {
                // thrown if the broker is unreachable during initial creation.
                logger.ErrorWrite("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.ErrorWrite("EasyNetQ Consumer Error Handler: Broker connection was closed while attempting to publish Error message.\n" +
                                  string.Format("Message was: '{0}'\n", interruptedException.Message) +
                                  CreateConnectionCheckMessage());
            }
            catch (Exception unexpectedException)
            {
                // Something else unexpected has gone wrong :(
                logger.ErrorWrite("EasyNetQ Consumer Error Handler: Failed to publish error message\nException is:\n" +
                                  unexpectedException);
            }
            return AckStrategies.Ack;
        }
예제 #35
0
 private AckStrategy GetAckStrategy(ConsumerExecutionContext context, Task task)
 {
     var ackStrategy = AckStrategies.Ack;
     try
     {
         if (task.IsFaulted)
         {
             logger.ErrorWrite(BuildErrorMessage(context, task.Exception));
             ackStrategy = consumerErrorStrategy.HandleConsumerError(context, task.Exception);
         }
         else if (task.IsCanceled)
         {
             ackStrategy = consumerErrorStrategy.HandleConsumerCancelled(context);
         }
     }
     catch (Exception consumerErrorStrategyError)
     {
         logger.ErrorWrite("Exception in ConsumerErrorStrategy:\n{0}",
                           consumerErrorStrategyError);
         return AckStrategies.Nothing;
     }
     return ackStrategy;
 }
예제 #36
0
        private AckStrategy GetAckStrategy(ConsumerExecutionContext context, Task task)
        {
            var ackStrategy = AckStrategies.Ack;

            try
            {
                if (task.IsFaulted)
                {
                    logger.ErrorWrite(BuildErrorMessage(context, task.Exception));
                    ackStrategy = consumerErrorStrategy.HandleConsumerError(context, task.Exception);
                }
                else if (task.IsCanceled)
                {
                    ackStrategy = consumerErrorStrategy.HandleConsumerCancelled(context);
                }
            }
            catch (Exception consumerErrorStrategyError)
            {
                logger.ErrorWrite("Exception in ConsumerErrorStrategy:\n{0}",
                                  consumerErrorStrategyError);
                return(AckStrategies.Nothing);
            }
            return(ackStrategy);
        }
 public AckStrategy HandleConsumerCancelled(ConsumerExecutionContext context)
 {
     return AckStrategies.Ack;
 }
 private string DeclareErrorExchangeQueueStructure(IModel model, ConsumerExecutionContext context)
 {
     DeclareDefaultErrorQueue(model);
     return DeclareErrorExchangeAndBindToDefaultErrorQueue(model, context);
 }
예제 #39
0
파일: Program.cs 프로젝트: coolcode/MqDemo
        public override AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception)
        {
            base.HandleConsumerError(context, exception);

            return AckStrategies.NackWithRequeue;
        }
예제 #40
0
 private void AckOrNackSent(ConsumerExecutionContext context)
 {
     var ackOrNackWasSent = AckOrNackWasSent;
     if (ackOrNackWasSent != null) ackOrNackWasSent(context);
 }
예제 #41
0
        private void DoAck(ConsumerExecutionContext context , Action<IModel, ulong> 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}";

            try
            {
                Preconditions.CheckNotNull(context.Consumer.Model, "context.Consumer.Model");

                ackStrategy(context.Consumer.Model, context.Info.DeliverTag);
            }
            catch (AlreadyClosedException alreadyClosedException)
            {
                logger.InfoWrite(failedToAckMessage,
                                 alreadyClosedException.Message,
                                 context.Info.ConsumerTag,
                                 context.Info.DeliverTag);
            }
            catch (IOException ioException)
            {
                logger.InfoWrite(failedToAckMessage,
                                 ioException.Message,
                                 context.Info.ConsumerTag,
                                 context.Info.DeliverTag);
            }
            catch (Exception exception)
            {
                logger.ErrorWrite("Unexpected exception when attempting to ACK or NACK\n{0}", exception);
            }
            finally
            {
                try
                {
                    foreach (var postAckCallback in context.PostAckCallbacks)
                    {
                        postAckCallback();
                    }
                }
                catch (Exception exception)
                {
                    logger.ErrorWrite("Exception in PostAckCallback:\n{0}", exception);
                }

                if (SynchronisationAction != null)
                {
                    SynchronisationAction();
                }
            }
        }
예제 #42
0
 private string DeclareErrorExchangeQueueStructure(IModel model, ConsumerExecutionContext context)
 {
     return "ErrorExchange_" + context.Info.RoutingKey;
     //   DeclareDefaultErrorQueue(model);
     return DeclareErrorExchangeAndBindToDefaultErrorQueue(model, context);
 }
예제 #43
0
        private void DoAck(ConsumerExecutionContext context, Func<IModel, ulong, AckResult> 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;

            try
            {
                Preconditions.CheckNotNull(context.Consumer.Model, "context.Consumer.Model");

                ackResult = ackStrategy(context.Consumer.Model, context.Info.DeliverTag);
            }
            catch (AlreadyClosedException alreadyClosedException)
            {
                logger.InfoWrite(failedToAckMessage,
                                 alreadyClosedException.Message,
                                 context.Info.ConsumerTag,
                                 context.Info.DeliverTag);
            }
            catch (IOException ioException)
            {
                logger.InfoWrite(failedToAckMessage,
                                 ioException.Message,
                                 context.Info.ConsumerTag,
                                 context.Info.DeliverTag);
            }
            catch (Exception exception)
            {
                logger.ErrorWrite("Unexpected exception when attempting to ACK or NACK\n{0}", exception);
            }
            finally
            {
                eventBus.Publish(new AckEvent(context, ackResult));
            }
        }
예제 #44
0
 public AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception)
 {
     return AckStrategies.NackWithRequeue;
 }
        private byte[] CreateErrorMessage(ConsumerExecutionContext context, Exception exception)
        {
            var messageAsString = Encoding.UTF8.GetString(context.Body);
            var error = new Error
            {
                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.MessageToBytes(error);
        }
예제 #46
0
 public AckStrategy HandleConsumerCancelled(ConsumerExecutionContext context)
 {
     return(AckStrategies.NackWithRequeue);
 }
        public void Should_not_reconnect_if_has_been_disposed()
        {
            const string originalMessage = "{ Text:\"Hello World\"}";
            var originalMessageBody = Encoding.UTF8.GetBytes(originalMessage);

            var exception = new Exception("I just threw!");

            var context = new ConsumerExecutionContext(
                (bytes, properties, arg3) => null,
                new MessageReceivedInfo("consumertag", 0, false, "orginalExchange", "originalRoutingKey", "queue"),
                new MessageProperties
                {
                    CorrelationId = "123",
                    AppId = "456"
                },
                originalMessageBody,
                MockRepository.GenerateStub<IBasicConsumer>()
                );

            var logger = MockRepository.GenerateMock<IEasyNetQLogger>();
            connectionFactory = MockRepository.GenerateMock<IConnectionFactory>();

            consumerErrorStrategy = new DefaultConsumerErrorStrategy(
                connectionFactory,
                MockRepository.GenerateStub<ISerializer>(),
                logger,
                MockRepository.GenerateStub<IConventions>(),
                MockRepository.GenerateStub<ITypeNameSerializer>(),
                MockRepository.GenerateStub<IErrorMessageSerializer>());

            consumerErrorStrategy.Dispose();

            var ackStrategy = consumerErrorStrategy.HandleConsumerError(context, exception);

            connectionFactory.AssertWasNotCalled(f => f.CreateConnection());
            logger.AssertWasCalled(l => l.ErrorWrite(Arg.Text.Contains("DefaultConsumerErrorStrategy was already disposed"), Arg<Object>.Is.Anything));

            Assert.AreEqual(AckStrategies.NackWithRequeue, ackStrategy);
        }
예제 #48
0
        public void HandleBasicDeliver(
            string consumerTag,
            ulong deliveryTag,
            bool redelivered,
            string exchange,
            string routingKey,
            IBasicProperties properties,
            byte[] body)
        {
            logger.DebugWrite("HandleBasicDeliver on consumer: {0}, deliveryTag: {1}", consumerTag, deliveryTag);

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

            if (onMessage == null)
            {
                logger.ErrorWrite("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(() => handlerRunner.InvokeUserMessageHandler(context));
        }
 private string DeclareErrorExchangeQueueStructure(IModel model, ConsumerExecutionContext context)
 {
     return "ErrorExchange_" + context.Info.RoutingKey;
 }
예제 #50
0
 public AckEvent(ConsumerExecutionContext consumerExecutionContext, AckResult ackResult)
 {
     ConsumerExecutionContext = consumerExecutionContext;
     AckResult = ackResult;
 }
        private byte[] CreateErrorMessage(ConsumerExecutionContext context, Exception exception)
        {
            var messageAsString = Encoding.UTF8.GetString(context.Body);
            var error = new Error
            {
                RoutingKey = context.Info.RoutingKey,
                Exchange = context.Info.Exchange,
                Exception = exception.ToString(),
                Message = messageAsString,
                DateTime = DateTime.UtcNow,
                BasicProperties = context.Properties
            };

            return serializer.MessageToBytes(error);
        }
예제 #52
0
        /// <inheritdoc />
        public virtual AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception)
        {
            Preconditions.CheckNotNull(context, "context");
            Preconditions.CheckNotNull(exception, "exception");

            if (disposed || disposing)
            {
                logger.ErrorFormat(
                    "ErrorStrategy was already disposed, when attempting to handle consumer error. Error message will not be published and message with receivedInfo={receivedInfo} will be requeued",
                    context.ReceivedInfo
                    );

                return(AckStrategies.NackWithRequeue);
            }

            logger.Error(
                exception,
                "Exception thrown by subscription callback, receivedInfo={receivedInfo}, properties={properties}, message={message}",
                context.ReceivedInfo,
                context.Properties,
                Convert.ToBase64String(context.Body)
                );

            try
            {
                using var model = connection.CreateModel();
                if (configuration.PublisherConfirms)
                {
                    model.ConfirmSelect();
                }

                var errorExchange = DeclareErrorExchangeWithQueue(model, context);

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

                model.BasicPublish(errorExchange, context.ReceivedInfo.RoutingKey, properties, messageBody);

                if (!configuration.PublisherConfirms)
                {
                    return(AckStrategies.Ack);
                }

                return(model.WaitForConfirms(configuration.Timeout) ? AckStrategies.Ack : AckStrategies.NackWithRequeue);
            }
            catch (BrokerUnreachableException unreachableException)
            {
                // thrown if the broker is unreachable during initial creation.
                logger.Error(
                    unreachableException,
                    "Cannot connect to broker while attempting to publish error message"
                    );
            }
            catch (OperationInterruptedException interruptedException)
            {
                // thrown if the broker connection is broken during declare or publish.
                logger.Error(
                    interruptedException,
                    "Broker connection was closed while attempting to publish error message"
                    );
            }
            catch (Exception unexpectedException)
            {
                // Something else unexpected has gone wrong :(
                logger.Error(unexpectedException, "Failed to publish error message");
            }

            return(AckStrategies.NackWithRequeue);
        }
예제 #53
0
 public AckStrategy HandleConsumerCancelled(ConsumerExecutionContext context)
 {
     return AckStrategies.NackWithRequeue;
 }
예제 #54
0
 private void HandleErrorInSubscriptionHandler(ConsumerExecutionContext context,
     Exception exception)
 {
     logger.ErrorWrite(BuildErrorMessage(context, exception));
     try
     {
         var strategy = consumerErrorStrategy.HandleConsumerError(context, exception);
         DoAck(context, (model, deliveryTag) => ExceptionAckStrategy(model, deliveryTag, strategy));
     }
     catch (Exception consumerErrorStrategyError)
     {
         logger.ErrorWrite("Exception in ConsumerErrorStrategy:\n{0}",
             consumerErrorStrategyError);
     }
 }
예제 #55
0
 private string DeclareErrorExchangeQueueStructure(IModel model, ConsumerExecutionContext context)
 {
     DeclareDefaultErrorQueue(model);
     return(DeclareErrorExchangeAndBindToDefaultErrorQueue(model, context));
 }
예제 #56
0
        private string BuildErrorMessage(ConsumerExecutionContext context, Exception exception)
        {
            var message = Encoding.UTF8.GetString(context.Body);

            var properties = context.Properties;
            var propertiesMessage = new StringBuilder();
            if (properties != null)
            {
                properties.AppendPropertyDebugStringTo(propertiesMessage);
            }

            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", propertiesMessage) +
                   string.Format("Exception:\n{0}\n", exception);
        }
예제 #57
0
 public AckStrategy HandleConsumerCancelled(ConsumerExecutionContext context)
 {
     return(AckStrategies.Ack);
 }
예제 #58
0
        public void SetUp()
        {
            var conventions = new Conventions(new TypeNameSerializer())
            {
                ConsumerTagConvention = () => consumerTag
            };

            consumerErrorStrategy = MockRepository.GenerateStub<IConsumerErrorStrategy>();
            consumerErrorStrategy.Stub(x => x.HandleConsumerError(null, null))
                .IgnoreArguments()
                .WhenCalled(i =>
                {
                    basicDeliverEventArgs = (ConsumerExecutionContext)i.Arguments[0];
                    raisedException = (Exception) i.Arguments[1];
                }).Return(AckStrategies.Ack);

            mockBuilder = new MockBuilder(x => x
                .Register<IConventions>(_ => conventions)
                .Register(_ => consumerErrorStrategy)
                //.Register<IEasyNetQLogger>(_ => new ConsoleLogger())
                );

            mockBuilder.Bus.Subscribe<MyMessage>(subscriptionId, message =>
            {
                throw originalException;
            });

            const string text = "Hello there, I am the text!";
            originalMessage = new MyMessage { Text = text };

            var body = new JsonSerializer(new TypeNameSerializer()).MessageToBytes(originalMessage);

            // deliver a message
            mockBuilder.Consumers[0].HandleBasicDeliver(
                consumerTag,
                deliveryTag,
                false, // redelivered
                typeName,
                "#",
                new BasicProperties
                {
                    Type = typeName,
                    CorrelationId = correlationId
                },
                body);

            // wait for the subscription thread to handle the message ...
            var autoResetEvent = new AutoResetEvent(false);
            mockBuilder.EventBus.Subscribe<AckEvent>(x => autoResetEvent.Set());
            autoResetEvent.WaitOne(1000);
        }
예제 #59
0
        public void SetUp()
        {
            var customConventions = new Conventions(new TypeNameSerializer())
            {
                ErrorQueueNamingConvention = () => "CustomEasyNetQErrorQueueName",
                ErrorExchangeNamingConvention = info => "CustomErrorExchangePrefixName." + info.RoutingKey
            };

            mockBuilder = new MockBuilder();

            errorStrategy = new DefaultConsumerErrorStrategy(
                mockBuilder.ConnectionFactory,
                new JsonSerializer(new TypeNameSerializer()),
                MockRepository.GenerateStub<IEasyNetQLogger>(),
                customConventions,
                new TypeNameSerializer());

            const string originalMessage = "";
            var originalMessageBody = Encoding.UTF8.GetBytes(originalMessage);

            var context = new ConsumerExecutionContext(
                (bytes, properties, arg3) => null,
                new MessageReceivedInfo("consumerTag", 0, false, "orginalExchange", "originalRoutingKey", "queue"),
                new MessageProperties
                    {
                        CorrelationId = string.Empty,
                        AppId = string.Empty
                    },
                originalMessageBody,
                MockRepository.GenerateStub<IBasicConsumer>()
                );

            try
            {
                errorStrategy.HandleConsumerError(context, new Exception());
            }
            catch (Exception)
            {
                // swallow
            }
        }