简体   繁体   中英

My C# WPF application consumer consuming all messages in a RabbitMQ Queue but some messages missing in the application

I got a bug fixing for an existing application. Reason: Missing consume messages when application listening for a RabbitMQ Queue. If the application opens/running and push 10 messages to the queue, then all the messages consume by Application (Queue messages get clear) but 7,8 messages only appear through the application (and others are missing)

But if 10 the application publishes to the rabbitMQ queue while the Application close. Then opens the application after published all 10 messages to RMQ queue, Then all 10 messages are consumed and save in the application correctly. This is an already developed WPF application using a timer to listen to messages.

Questions:

  1. What is the issue for missing consumed messages?
  2. If I change code to manual ACK, what change i required to do? Because autoAck: false in basic consumer & _channel.BasicAck(deliveryTag, false); gives me exception Already closed: The AMQP operation was interrupted: AMQP close-reason, initiated by Application, code=200, text='Goodbye', classId=0, methodId=0

This is the code

MainWindow.xmal.cs

public partial class MainWindow : Window
{
    Thread _threadTimer;
    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        _threadTimer = new Thread(() =>
        {
            dispatcherTimer.Tick += dispatcherTimer_Tick;
            dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
            dispatcherTimer.Start();
        });
        _threadTimer.Start();
    }
    
    
    private void dispatcherTimer_Tick(object sender, EventArgs e)
    {
        #region rabbitMQ Configurtions
        string HostName = hNamefromApp.config
        string UserName = uNamefromApp.config
        string Password = pwdfromApp.config
        string QueueName = qNamefromApp.config
        string VHost = vHostfromApp.config;
    
        Thread _threadHandleMessage;
        _threadHandleMessage = new Thread(() =>
        {
            HandleConsumeMessage(HostName, UserName, Password, QueueName, VHost, this.Dispatcher);
        });
        _threadHandleMessage.Start();
        }
        #endregion
    }
    
    
    private bool HandleConsumeMessage(string HostName, string UserName, string Password, string QueueName, string VHOST, Dispatcher dispatcher)
    {
        bool result = false;
        var factory = CreateConnectionFactory(HostName, UserName, Password, VHOST);
        using (var connection = factory.CreateConnection())
        {
            using (var channel = connection.CreateModel())
            {
                channel.QueueDeclare(queue: QueueName,
                                    durable: false,
                                    exclusive: false,
                                    autoDelete: false,
                                    arguments: null);
    
                var response = channel.QueueDeclarePassive(QueueName);
                var receivedMsgCount = response.MessageCount;
    
                MessageReceiver messageReceiver = new MessageReceiver(channel, dispatcher, txtOutput);
                channel.BasicConsume(queue: QueueName,
                                    autoAck: true,
                                    consumer: messageReceiver);
    
                // Thread sleep duration calculate based on received message count
                var consumeMsgCount = response.ConsumerCount;
                int threadDuration = 300;
                if (receivedMsgCount > 0)
                { 
                    threadDuration = (int)receivedMsgCount * 400; 
                }
                Thread.Sleep(threadDuration);
            }
        }
        return result;
    }
}

MessageReceiver.cs

public class MessageReceiver : DefaultBasicConsumer
{
    private readonly IModel _channel;
    private readonly Dispatcher _dispatcher;
    private readonly TextBox _textBox;

    public MessageReceiver(IModel channel, Dispatcher dispatcher, TextBox textBox)
    {
        //Main thread and output text box is passed here so that this thread is capable of updating UI
        _channel = channel;
        _dispatcher = dispatcher;
        _textBox = textBox;
    }
    
    Thread _threadConsumeMessage;
    public override void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, IBasicProperties properties, ReadOnlyMemory<byte> body)
    {
        _threadConsumeMessage = new Thread(() =>
        {
            CaptureDataFromMessage(body);
        });
        _threadConsumeMessage.Start();
    }

    private void CaptureDataFromMessage(ReadOnlyMemory<byte> body)
    {
        try
        {
            var bodyArray = body.ToArray();
            var message = Encoding.UTF8.GetString(bodyArray);
            //LogModel txtLog = new LogModel();
            //APIModel nlConsumeDetails = JsonConvert.DeserializeObject<APIModel>(message);
            //Temporary save the consumed  messages to local to test the issue
        }
        catch (Exception ex)
        {
            log.Error(ex);
        }
    }
}

You should use Dispatcher.Invoke to update your GUI from a secondary thread. See this Updating GUI (WPF) using a different thread

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM