【问题标题】:Is a System.MessageQueue (MSMQ) message lost if my function fails while processing it?如果我的函数在处理时失败,System.MessageQueue (MSMQ) 消息是否会丢失?
【发布时间】:2025-11-24 00:15:01
【问题描述】:

我使用以下代码发送消息:

var transaction = new MessageQueueTransaction())
transaction.Begin(  );

var message = new Message
{
   Body = myContent,
   Recoverable = true
};

m_oMessageQueue.Send( message , myTransaction );

transaction.Commit( );

并使用BeginRecieveReceiveCompleted 事件处理程序接收它。

如果我的事件处理程序在调用EndRecieve 之前失败,消息是否应该保留在队列中并可供后续调用接收?我看到的行为是消息永远消失了。 (或者也许有一个超时时间之后它会再次可用?)

更新接收消息的代码如下所示。

var messageQueue = new MessageQueue( myPath );
messageQueue.ReceiveCompleted += messageQueue_ReceiveCompleted_ThrowException;
messageQueue.BeginReceive();

出于测试目的,我在 messageQueue_ReceiveCompleted_ThrowException 事件处理程序中抛出异常。

然后我用一个有效的事件处理程序重复上面的代码,但我没有被调用。

【问题讨论】:

  • 你的接收队列的 EnableConnectionCache 设置是什么?
  • 我什么都没设置,有什么用?

标签: c# msmq message-queue


【解决方案1】:

看起来问题在于您将BeginReceive 与事务队列一起使用。 From MSDN:

注意不要使用异步 使用交易调用 BeginReceive。 如果你想执行事务 异步操作,调用 BeginPeek,并把交易和 (同步)接收方法 在您创建的事件处理程序中 用于窥视操作。您的活动 处理程序可能包含以下功能 如以下 C# 代码所示。

对于这样的失败,我相信消息通常会进入死信队列或产生否定确认,这取决于您如何配置 MessageQueue(这可以解释为什么您看不到它们)。你可以read more about those options here

【讨论】:

  • 谢谢,这对我有帮助。另一个相关问题,如果我使用 Peek,是否有可能消息会被多个消费者接收?
  • 多个消费者可以Peek 发送消息,但实际上只有一个消费者能够Receive 特定消息。这可能需要额外的注意,因为两个消费者可能同时在那里——你必须决定他们是在寻找特定的消息(Peek 找到),还是任何旧消息,并且可能确保在Receive 调用中添加超时,这样失败者就不会永远阻塞。
  • 使用 PeekCompleted 中传递的 Id BeginPeek 和稍后的 ReceiveById 会是更好的方法吗?
【解决方案2】:

最简单的解决办法可能是使用 BeginPeek 或 Peek 读取消息的内容而不将其从队列中移除,一旦消息被处理,然后将消息从队列中移除。

【讨论】:

    【解决方案3】:

    如果队列是事务性的但远程的,那么您只能在使用 MSMQ 4.0 的事务中接收消息。

    How do I get transactional remote receives with MSMQ?

    干杯 约翰·布雷克韦尔 (MSFT)

    【讨论】: