private void DoAck(BasicDeliverEventArgs basicDeliverEventArgs, SubscriptionInfo subscriptionInfo, 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.";

            try
            {
                ackStrategy(subscriptionInfo.Consumer.Model, basicDeliverEventArgs.DeliveryTag);

                if (subscriptionInfo.ModelIsSingleUse)
                {
                    subscriptionInfo.Consumer.CloseModel();
                    subscriptionInfo.SubscriptionAction.ClearAction();
                }
            }
            catch (AlreadyClosedException alreadyClosedException)
            {
                logger.InfoWrite(failedToAckMessage, alreadyClosedException.Message);
            }
            catch (IOException ioException)
            {
                logger.InfoWrite(failedToAckMessage, ioException.Message);
            }
            finally
            {
                if (SynchronisationAction != null)
                {
                    SynchronisationAction();
                }
            }
        }
Example #2
0
        public StartConsumingStatus StartConsuming(IPersistentConnection connection, ICollection <Tuple <IQueue, Func <byte[], MessageProperties, MessageReceivedInfo, Task> > > queueConsumerPairs, IConsumerConfiguration configuration)
        {
            Preconditions.CheckNotNull(connection, nameof(connection));
            Preconditions.CheckNotNull(queueConsumerPairs, nameof(queueConsumerPairs));
            Preconditions.CheckNotNull(configuration, nameof(configuration));


            IDictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "x-priority", configuration.Priority },
                { "x-cancel-on-ha-failover", configuration.CancelOnHaFailover || connectionConfiguration.CancelOnHaFailover }
            };

            try
            {
                Model = connection.CreateModel();

                Model.BasicQos(0, configuration.PrefetchCount, true);


                _basicConsumers = new List <BasicConsumer>();

                foreach (var p in queueConsumerPairs)
                {
                    var queue       = p.Item1;
                    var onMessage   = p.Item2;
                    var consumerTag = conventions.ConsumerTagConvention();
                    try
                    {
                        var basicConsumers = new BasicConsumer(SingleBasicConsumerCancelled, consumerDispatcher, queue, eventBus, handlerRunner, onMessage, logger, Model);

                        Model.BasicConsume(
                            queue.Name,  // queue
                            false,       // noAck
                            consumerTag, // consumerTag
                            true,
                            configuration.IsExclusive,
                            arguments,       // arguments
                            basicConsumers); // consumer
                        _basicConsumers.Add(basicConsumers);

                        logger.InfoWrite("Declared Consumer. queue='{0}', consumer tag='{1}' prefetchcount={2} priority={3} x-cancel-on-ha-failover={4}",
                                         queue.Name, consumerTag, configuration.PrefetchCount, configuration.Priority, configuration.CancelOnHaFailover);
                    }
                    catch (Exception ex)
                    {
                        logger.ErrorWrite("Consume failed. queue='{0}', consumer tag='{1}', message='{2}'",
                                          queue.Name, consumerTag, ex.Message);
                        return(StartConsumingStatus.Failed);
                    }
                }
            }
            catch (Exception exception)
            {
                logger.ErrorWrite("Consume failed. queue='{0}', message='{1}'",
                                  string.Join(";", queueConsumerPairs.Select(x => x.Item1.Name)), exception.Message);
                return(StartConsumingStatus.Failed);
            }
            return(StartConsumingStatus.Succeed);
        }
Example #3
0
        public void StartConsuming(
            IPersistentConnection connection,
            IQueue queue,
            Func <byte[], MessageProperties, MessageReceivedInfo, Task> onMessage)
        {
            Preconditions.CheckNotNull(connection, "connection");
            Preconditions.CheckNotNull(queue, "queue");
            Preconditions.CheckNotNull(onMessage, "onMessage");

            this.queue     = queue;
            this.onMessage = onMessage;
            var consumerTag = conventions.ConsumerTagConvention();

            try
            {
                Model = connection.CreateModel();

                Model.BasicQos(0, connectionConfiguration.PrefetchCount, false);

                Model.BasicConsume(
                    queue.Name,         // queue
                    false,              // noAck
                    consumerTag,        // consumerTag
                    this);              // consumer

                logger.InfoWrite("Declared Consumer. queue='{0}', consumer tag='{1}' prefetchcount={2}",
                                 queue.Name, consumerTag, connectionConfiguration.PrefetchCount);
            }
            catch (Exception exception)
            {
                logger.InfoWrite("Consume failed. queue='{0}', consumer tag='{1}', message='{2}'",
                                 queue.Name, consumerTag, exception.Message);
            }
        }
Example #4
0
        void TryToConnect(object timer)
        {
            if (timer != null)
            {
                ((Timer)timer).Dispose();
            }

            logger.DebugWrite("Trying to connect");
            if (disposed)
            {
                return;
            }
            try
            {
                connection = connectionFactory.CreateConnection();
                connection.ConnectionShutdown += OnConnectionShutdown;

                if (Connected != null)
                {
                    Connected();
                }
                logger.InfoWrite("Connected to RabbitMQ. Broker: '{0}', VHost: '{1}'", connectionFactory.HostName, connectionFactory.VirtualHost);
            }
            catch (BrokerUnreachableException brokerUnreachableException)
            {
                logger.ErrorWrite("Failed to connect to Broker: '{0}', VHost: '{1}'. Retrying in {2} ms\n" +
                                  "Check HostName, VirtualHost, Username and Password.\n" +
                                  "ExceptionMessage: {3}",
                                  connectionFactory.HostName,
                                  connectionFactory.VirtualHost,
                                  connectAttemptIntervalMilliseconds,
                                  brokerUnreachableException.Message);
                StartTryToConnect();
            }
        }
Example #5
0
        void TryToConnect(object timer)
        {
            if (timer != null)
            {
                ((Timer)timer).Dispose();
            }

            logger.DebugWrite("Trying to connect");
            if (disposed)
            {
                return;
            }

            connectionFactory.Reset();
            do
            {
                try
                {
                    connection = connectionFactory.CreateConnection(); // A possible dispose race condition exists, whereby the Dispose() method may run while this loop is waiting on connectionFactory.CreateConnection() returning a connection.  In that case, a connection could be created and assigned to the connection variable, without it ever being later disposed, leading to app hang on shutdown.  The following if clause guards against this condition and ensures such connections are always disposed.
                    if (disposed)
                    {
                        connection.Dispose();
                        break;
                    }

                    connectionFactory.Success();
                }
                catch (SocketException socketException)
                {
                    LogException(socketException);
                }
                catch (BrokerUnreachableException brokerUnreachableException)
                {
                    LogException(brokerUnreachableException);
                }
            } while (!disposed && connectionFactory.Next());

            if (connectionFactory.Succeeded)
            {
                connection.ConnectionShutdown  += OnConnectionShutdown;
                connection.ConnectionBlocked   += OnConnectionBlocked;
                connection.ConnectionUnblocked += OnConnectionUnblocked;

                OnConnected();
                logger.InfoWrite("Connected to RabbitMQ. Broker: '{0}', Port: {1}, VHost: '{2}'",
                                 connectionFactory.CurrentHost.Host,
                                 connectionFactory.CurrentHost.Port,
                                 connectionFactory.Configuration.VirtualHost);
            }
            else
            {
                if (!disposed)
                {
                    logger.ErrorWrite("Failed to connect to any Broker. Retrying in {0}",
                                      connectionFactory.Configuration.ConnectIntervalAttempt);
                    StartTryToConnect();
                }
            }
        }
Example #6
0
        public void Start()
        {
            log.InfoWrite("Starting SchedulerService");
            bus.Subscribe <ScheduleMe>(schedulerSubscriptionId, OnMessage);
            bus.Subscribe <UnscheduleMe>(schedulerSubscriptionId, OnMessage);

            publishTimer = new System.Threading.Timer(OnPublishTimerTick, null, 0, configuration.PublishIntervalSeconds * 1000);
            purgeTimer   = new System.Threading.Timer(OnPurgeTimerTick, null, 0, configuration.PurgeIntervalSeconds * 1000);
        }
Example #7
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();
                }
            }
        }
        void TryToConnect(object timer)
        {
            if (timer != null)
            {
                ((Timer)timer).Dispose();
            }

            logger.DebugWrite("Trying to connect");
            if (disposed)
            {
                return;
            }

            connectionFactory.Reset();
            do
            {
                try
                {
                    connection = connectionFactory.CreateConnection();
                    connectionFactory.Success();
                }
                catch (SocketException socketException)
                {
                    LogException(socketException);
                }
                catch (BrokerUnreachableException brokerUnreachableException)
                {
                    LogException(brokerUnreachableException);
                }
            } while (connectionFactory.Next());

            if (connectionFactory.Succeeded)
            {
                connection.ConnectionShutdown  += OnConnectionShutdown;
                connection.ConnectionBlocked   += OnConnectionBlocked;
                connection.ConnectionUnblocked += OnConnectionUnblocked;

                OnConnected();
                logger.InfoWrite("Connected to RabbitMQ. Broker: '{0}', Port: {1}, VHost: '{2}'",
                                 connectionFactory.CurrentHost.Host,
                                 connectionFactory.CurrentHost.Port,
                                 connectionFactory.Configuration.VirtualHost);
            }
            else
            {
                logger.ErrorWrite("Failed to connect to any Broker. Retrying in {0} ms\n",
                                  connectAttemptIntervalMilliseconds);
                StartTryToConnect();
            }
        }
Example #9
0
        public StartConsumingStatus StartConsuming(
            IPersistentConnection connection,
            IQueue queue,
            Func <byte[], MessageProperties, MessageReceivedInfo, Task> onMessage,
            IConsumerConfiguration configuration
            )
        {
            Preconditions.CheckNotNull(connection, "connection");
            Preconditions.CheckNotNull(queue, "queue");
            Preconditions.CheckNotNull(onMessage, "onMessage");
            Preconditions.CheckNotNull(configuration, "configuration");

            this.queue         = queue;
            this.onMessage     = onMessage;
            this.configuration = configuration;

            var consumerTag = conventions.ConsumerTagConvention();
            IDictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "x-priority", configuration.Priority },
                { "x-cancel-on-ha-failover", configuration.CancelOnHaFailover || connectionConfiguration.CancelOnHaFailover }
            };

            try
            {
                Model = connection.CreateModel();

                Model.BasicQos(0, configuration.PrefetchCount, false);

                Model.BasicConsume(
                    queue.Name,         // queue
                    false,              // noAck
                    consumerTag,        // consumerTag
                    true,
                    configuration.IsExclusive,
                    arguments,          // arguments
                    this);              // consumer

                logger.InfoWrite("Declared Consumer. queue='{0}', consumer tag='{1}' prefetchcount={2} priority={3} x-cancel-on-ha-failover={4}",
                                 queue.Name, consumerTag, configuration.PrefetchCount, configuration.Priority, configuration.CancelOnHaFailover);
            }
            catch (Exception exception)
            {
                logger.ErrorWrite("Consume failed. queue='{0}', consumer tag='{1}', message='{2}'",
                                  queue.Name, consumerTag, exception.Message);
                return(StartConsumingStatus.Failed);
            }
            return(StartConsumingStatus.Succeed);
        }
Example #10
0
        public void OnPublishTimerTick(object state)
        {
            try
            {
                if (!bus.IsConnected)
                {
                    log.InfoWrite("Not connected");
                    return;
                }

                // Keep track of exchanges that have already been declared this tick
                var declaredExchanges = new ConcurrentDictionary <Tuple <string, string>, IExchange>();
                Func <Tuple <string, string>, IExchange> declareExchange = exchangeNameType =>
                {
                    log.DebugWrite("Declaring exchange {0}, {1}", exchangeNameType.Item1, exchangeNameType.Item2);
                    return(bus.Advanced.ExchangeDeclare(exchangeNameType.Item1, exchangeNameType.Item2));
                };

                using (var scope = new TransactionScope())
                {
                    var scheduledMessages = scheduleRepository.GetPending();

                    foreach (var scheduledMessage in scheduledMessages)
                    {
                        // Binding key fallback is only provided here for backwards compatibility, will be removed in the future
                        log.DebugWrite("Publishing Scheduled Message with Routing Key: '{0}'", scheduledMessage.BindingKey);

                        var exchangeName = scheduledMessage.Exchange ?? scheduledMessage.BindingKey;
                        var exchangeType = scheduledMessage.ExchangeType ?? ExchangeType.Topic;

                        var exchange = declaredExchanges.GetOrAdd(new Tuple <string, string>(exchangeName, exchangeType), declareExchange);

                        var messageProperties = scheduledMessage.MessageProperties;

                        if (scheduledMessage.MessageProperties == null)
                        {
                            messageProperties = new MessageProperties {
                                Type = scheduledMessage.BindingKey
                            }
                        }
                        ;

                        var routingKey = scheduledMessage.RoutingKey ?? scheduledMessage.BindingKey;

                        bus.Advanced.Publish(
                            exchange,
                            routingKey,
                            false,
                            messageProperties,
                            scheduledMessage.InnerMessage);
                    }

                    scope.Complete();
                }
            }
            catch (Exception exception)
            {
                log.ErrorWrite("Error in schedule poll\r\n{0}", exception);
            }
        }
        private void DoAck(BasicDeliverEventArgs basicDeliverEventArgs, SubscriptionInfo subscriptionInfo)
        {
            const string failedToAckMessage = "Basic ack failed because chanel was closed with message {0}." +
                                              " Message remains on RabbitMQ and will be retried.";

            try
            {
                subscriptionInfo.Consumer.Model.BasicAck(basicDeliverEventArgs.DeliveryTag, false);
            }
            catch (AlreadyClosedException alreadyClosedException)
            {
                logger.InfoWrite(failedToAckMessage, alreadyClosedException.Message);
            }
            catch (IOException ioException)
            {
                logger.InfoWrite(failedToAckMessage, ioException.Message);
            }
        }
Example #12
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));
            }
        }
Example #13
0
        /// <summary>
        ///     Handles Consumer Cancel Notification: http://www.rabbitmq.com/consumer-cancel.html
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void OnBasicCancel(object sender, BasicCancelEventArgs args)
        {
            logger.InfoWrite("BasicCancel(Consumer Cancel Notification from broker) event received. Recreating queue and queue listener. Consumer tag: " + args.ConsumerTag);

            if (subscribeActions.ContainsKey(args.ConsumerTag))
            {
                // According to: http://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v3.1.4/rabbitmq-dotnet-client-3.1.4-user-guide.pdf section 2.9.
                // All IBasicConsumer methods are dispatched by single background thread
                // and MUST NOT invoke blocking AMQP operations: IModel.QueueDeclare, IModel.BasicCancel or IModel.BasicPublish...
                // For this reason we are recreating queues and queue listeners on separate thread.
                // Which is disposed after we are done.
                new Thread(() => subscribeActions[args.ConsumerTag].ExecuteAction(false)).Start();
            }
        }
Example #14
0
        public void HandleBasicCancel(string consumerTag)
        {
            Cancel();
            logger.InfoWrite("BasicCancel(Consumer Cancel Notification from broker) event received. " +
                             "Consumer tag: {0}", consumerTag);

            if (Queue.IsConsumerRepairable)
            {
                ConsumerReConnect(consumerTag);
            }
        }
Example #15
0
 public void HandleBasicCancel(string consumerTag)
 {
     Cancel();
     logger.InfoWrite("BasicCancel(Consumer Cancel Notification from broker) event received. " +
                      "Consumer tag: {0}", consumerTag);
 }
        /// <summary>
        /// This method is fired when an exception is thrown. Implement a strategy for
        /// handling the exception here.
        /// </summary>
        /// <param name="context">The consumer execution context.</param>
        /// <param name="exception">The exception</param>
        /// <returns><see cref="AckStrategy"/> for processing the original failed message</returns>
        public AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception)
        {
            try
            {
                // First write the exception to the logger
                _logger.ErrorWrite(exception);

                Connect();

                using (var model = _connection.CreateModel())
                {
                    var properties = context.Properties;

                    var flrRetry = 1;
                    if (properties.HeadersPresent && properties.Headers.ContainsKey("easynetq.retry.count"))
                    {
                        flrRetry = Convert.ToInt16(properties.Headers["easynetq.retry.count"]) + 1;
                    }

                    // Max retries set to 2 means we will run it once more, 3 means run it twice more, 3 etc etc
                    if (flrRetry < _flrMaxRetries)
                    {
                        _logger.InfoWrite(
                            $"(FLR) First Level Retry [{flrRetry}] for message of type [{properties.Type}].");

                        RetryMessage(context, model, properties, flrRetry);

                        _logger.DebugWrite("Message resent.");
                    }
                    else
                    {
                        _logger.DebugWrite(
                            $"Reached maximum First Level Retry, handing over to dead letter queue, message of type [{properties.Type}].");

                        // Send message to the deadletter queue
                        SendMessageToErrorQueue(context, exception, model, properties);
                    }
                }
            }
            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" +
                                   $"Message was: '{interruptedException.Message}'\n" +
                                   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);
        }