RabbitMQ的BasicdeliverEventArgs对象Body莫名变更问题求助
问题根源与解决方案
你的问题核心在于RabbitMQ客户端的BasicDeliverEventArgs对象是可能被复用的,其Body指向的是共享内存缓冲区。当你把原始的BasicDeliverEventArgs实例存入FailQueue后,后续RabbitMQ处理新消息时,可能会覆盖这块共享内存,导致你看到Body内容“自动变更”——你并没有手动修改,但底层内存被客户端复用了。
具体修复步骤:
- 避免直接传递
BasicDeliverEventArgs对象:在从RabbitMQ获取消息时,立即复制Body的字节数组,并将需要的消息元数据(比如DeliveryTag、Exchange、RoutingKey等)封装成自定义的消息类,而不是直接使用RabbitMQ的原生对象。 - 修改队列存储与处理逻辑:让
DataQueue和FailQueue存储自定义消息对象,而非BasicDeliverEventArgs实例。
修复后的代码示例:
首先定义自定义消息类:
public class RabbitMqMessage { public byte[] Body { get; set; } public ulong DeliveryTag { get; set; } // 按需添加其他需要的元数据,比如Exchange、RoutingKey等 }
然后在读取RabbitMQ消息时,转换为自定义对象再入队:
// 从RabbitMQ接收到消息时的处理 void OnReceived(object sender, BasicDeliverEventArgs e) { var customMsg = new RabbitMqMessage { Body = e.Body.ToArray(), // 复制字节数组,脱离共享缓冲区 DeliveryTag = e.DeliveryTag }; DataQueue.Enqueue(customMsg); }
修改ProcessQueue方法:
void ProcessQueue(object obj) { var msg = (RabbitMqMessage)obj; var cnv = new ByteArraySerializer(); var dto = cnv.Deserialize<MyClass>(msg.Body); try { var err = Repository.Database.Insert(dto); if (err == null) Console.WriteLine("Success Sent"); else FailQueue.Enqueue(msg); // 存入自定义对象,内存不会被复用 } catch (Exception ex) { Console.WriteLine("Error Occoured:" + ex); } }
额外注意点:
- 你原代码里
var e.Body.ToArray();没有赋值给变量,后续直接用body是错误的,应该是var body = e.Body.ToArray();,不过这只是笔误,但核心问题还是对象复用。 - 永远不要依赖RabbitMQ原生事件对象的长期存活,这类对象通常是为了单次消息处理设计的,底层内存会被客户端复用或回收。
内容的提问来源于stack exchange,提问作者Mostafa Asadi
相关产品推荐
相关产品推荐

