RabbitMQ BasicAck发出下一条消息UnAck

时间:2015-09-16 07:53:19

标签: c# rabbitmq

这是方案

一开始, 就绪队列:2 UnAcked:0

consumer.Queue.Dequeue(1000, out bdea);运行后,

ReadyQueue:1 UnAcked:1 这很明显,我们读了一条消息而不是已经确认。

问题是当channel.BasicAck(bdea.DeliveryTag, false);运行时,

ReadyQueue:0 UnAcked:1

处于Ready状态的消息变为UnAcked,ReadyQueue变为" 0" !!

现在,在while循环中,当我们查找带有consumer.Queue.Dequeue(1000, out bdea);的第二条消息时,bdea返回null,因为Ready状态中没有任何内容。

这就是问题,当Ack发生时,它总是将一条消息从Ready队列拖到UnAck。因此,下次我丢失这条从未出现过的UnAcked消息。

但如果我停止进程(Console App),UnAck消息将返回Ready State。

假设在开始时有10条消息处于Ready状态,最后它将只处理5,在那里您找到5条处于UnAcked状态的消息。每个Ack发出下一条消息UnAck。如果我再次停止并运行(5条消息处于就绪状态),猜猜是什么,3条消息将被处理,2条将是UnAcked。 (Dequeue只挑选了一半的消息)

这是我的代码(只有RabbitMQ功能的代码,如果你也尝试这个代码就有问题),

public class TestMessages
{
    private ConnectionFactory factory = new ConnectionFactory();
    string billingFileId = string.Empty;
    private IConnection connection = null;
    private IModel channel = null;
    public void Listen()
    {
        try
        {
            #region CONNECT
            factory.AutomaticRecoveryEnabled = true;
            factory.UserName = ConfigurationManager.AppSettings["MQUserName"];
            factory.Password = ConfigurationManager.AppSettings["MQPassword"];
            factory.VirtualHost = ConfigurationManager.AppSettings["MQVirtualHost"];
            factory.HostName = ConfigurationManager.AppSettings["MQHostName"];
            factory.Port = Convert.ToInt32(ConfigurationManager.AppSettings["MQPort"]);
            #endregion


            RabbitMQ.Client.Events.BasicDeliverEventArgs bdea;
            using (connection = factory.CreateConnection())
            {
                string jobId = string.Empty;
                using (IModel channel = connection.CreateModel())
                {
                    while (true) //KEEP LISTNING
                    {
                        if (!channel.IsOpen)
                            throw new Exception("Channel is closed"); //Exit the loop.

                        QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel);

                        //Prefetch 1 message
                        channel.BasicQos(0, 1, false);

                        String consumerTag = channel.BasicConsume(ConfigurationManager.AppSettings["MQQueueName"], false, consumer);

                        try
                        {
                            //Pull out the message
                            consumer.Queue.Dequeue(1000, out bdea);
                            if (bdea == null)
                            {
                                //Empty Queue
                            }
                            else
                            {
                                IBasicProperties props = bdea.BasicProperties;
                                byte[] body = bdea.Body;
                                string message = System.Text.Encoding.Default.GetString(bdea.Body);

                                try
                                {

                                    channel.BasicAck(bdea.DeliveryTag, false);

                                    ////Heavy work starts now......

                                }
                                catch (Exception ex)
                                {
                                    //Log

                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            //Log it
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            WriteLog.Error(ex);
        }
        finally
        {
            //CleanUp();
        }
    }
}

我错过了什么吗?

1 个答案:

答案 0 :(得分:1)

我试过了"订阅"而不是频道,它现在工作,清除消息队列。我提到this post

这是工作代码,

 public void SubscribeListner()
    {
        Subscription subscription = null;
        const string uploaderExchange = "myQueueExchange";
        string queueName = "myQueue";
        while (true)
        {
            try
            {
                if (subscription == null)
                {
                    try
                    {
                       //CONNECT Code

                        //try to open connection
                        connection = factory.CreateConnection();
                    }
                    catch (BrokerUnreachableException ex)
                    {
                        //You probably want to log the error and cancel after N tries, 
                        //otherwise start the loop over to try to connect again after a second or so.
                        //log.Error(ex);
                        continue;
                    }


                    //crate chanel
                    channel = connection.CreateModel();
                    // This instructs the channel not to prefetch more than one message
                    channel.BasicQos(0, 1, false);
                    // Create a new, durable exchange
                    channel.ExchangeDeclare(uploaderExchange, ExchangeType.Direct, true, false, null);
                    // Create a new, durable queue
                    channel.QueueDeclare(queueName, true, false, false, null);
                    // Bind the queue to the exchange
                    channel.QueueBind(queueName, uploaderExchange, queueName);
                    //create subscription
                    subscription = new Subscription(channel, uploaderExchange, false);
                }
                BasicDeliverEventArgs eventArgs;
                var gotMessage = subscription.Next(250, out eventArgs);//250 millisecond
                if (gotMessage)
                {
                    if (eventArgs == null)
                    {
                        //This means the connection is closed.
                        //DisposeAllConnectionObjects();
                        continue;//move to new iterate
                    }

                    //process message
                    subscription.Ack(); 
                    //channel.BasicAck(eventArgs.DeliveryTag, false);
                }
            }
            catch (OperationInterruptedException ex)
            {
                //log.Error(ex);
                //DisposeAllConnectionObjects();
            }
            catch(Exception ex)
            {

            }

        }
    }