繁体   English   中英

我的 C# WPF 应用程序消费者使用 RabbitMQ 队列中的所有消息,但应用程序中缺少一些消息

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

我为现有应用程序修复了错误。 原因:在应用程序侦听 RabbitMQ 队列时缺少消费消息。 如果应用程序打开/运行并将 10 条消息推送到队列,则所有消息都由应用程序消耗(队列消息清除),但 7,8 条消息仅通过应用程序出现(其他消息丢失)

但是如果 10 应用程序在应用程序关闭时发布到 rabbitMQ 队列。 然后在将所有 10 条消息发布到 RMQ 队列后打开应用程序,然后所有 10 条消息都被消费并正确保存在应用程序中。 这是一个已经开发的 WPF 应用程序,使用计时器来收听消息。

问题:

  1. 丢失已消费消息的问题是什么?
  2. 如果我将代码更改为手动 ACK,我需要做什么更改? 因为autoAck: false in basic consumer & _channel.BasicAck(deliveryTag, false); 给我异常已经关闭:AMQP 操作被中断:AMQP 关闭原因,由 Application 发起,code=200,text='Goodbye',classId=0,methodId=0

这是代码

主窗口.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;
    }
}

消息接收器.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);
        }
    }
}

您应该使用 Dispatcher.Invoke 从辅助线程更新您的 GUI。 使用不同的线程查看此更新 GUI (WPF)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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