最近一周遇到的神坑,必须记录一下血泪史。
背景:
有关航司要接区局的数据,区局使用的是rabbitmq进行数据的发送。因为之前做过IBMMQ和activeMQ。都没有遇到特别大的坑。于是轻松就答应去做了。
要做的是同步程序,因为是C#开发,直接用的现有的winfrom窗体去做的。一顿操作猛如虎,引入nuget。然后熟悉的代码:
var factory = new ConnectionFactory();
factory.HostName = IP;
factory.UserName = user;
factory.Password = password;
factory.Port = 15672;
factory.VirtualHost = "/virtual";
try
{
using (var connection = factory.CreateConnection())
{
factory.AutomaticRecoveryEnabled = true;
using (var channel = connection.CreateModel())
{
//channel.QueueDeclare("task_queue", false, false, false, null);
channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
var consumer = new EventingBasicConsumer(channel);
channel.BasicConsume("prss2zh-queue", false, consumer);
//消费者
channel.BasicConsume("prss2zh-queue", false , consumer);
//消费消息 autoAck参数为消费后是否删除
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Thread.Sleep(2000);
SetSendText(message); //委托显示在listbox中
channel.BasicAck(ea.DeliveryTag, false);
};
}
}
}
catch (Exception ex)
{
throw;
}
轻松加easy就完成。几句代码的事情。
因为需要手动ack,所以前面 channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);这句是每次获取1条消息。
channel.BasicConsume(“prss2zh-queue”, false , consumer); 这里是不进行批量确认。
结果在运行的时候就出问题了,这里遇到两个问题:
1、消息不会持续接收。
2、在手动ack的时候报错,提示 (无法访问已释放的对象。对象名:“RabbitMQ.Client.Impl.AutorecoveringModel”)。
后来在跟踪调试的时候,发现在进入通道的时候,程序是没问题的,但是在通道内获取消息的时候已经走完using,进行了资源释放。而且factory.AutomaticRecoveryEnabled = true 重连机制似乎并没有生效。
这个问题困扰了好久一直没能解决。
后来实在拖不起,在本地搭建了rabbitmq,然后地址是:http://192.168.0.194:15672/#/queues。并且从github上找了一个C#的高星程序连接: 进行测试。
好嘛,代码基本完全一样,结果确大不相同。这个是控制台程序,一个收,一个发,手动ack,完美。
结果我把代码搞到winfrom程序中,仍然是上面的两个问题。怀疑是winfrom窗体中的线程的问题,每次在获取数据进入到通道的时候,会先走完using,然后再进入到消息获取中。这里再进行手动ack的时候,channel已经关闭。又是查文章,与同事一起测试,都没有解决。
无奈之下,只好把这个接收程序换成控制台的。结果运行、获取数据一气呵成。
现在实在是忙,先记录这个问题,等到后续有时间再慢慢研究具体是什么原因。