1

我知道你不应该在非异常情况下使用异常,但我想通过其他人来看看我想做的事情是否真的那么糟糕。

我有一个例程试图从 MSMQ 消息队列中获取消息。如果队列上没有可用的消息,它会检查辅助源以查看那里是否有可用的消息。该例程的示例如下:

void CheckForMessages(out Message msg, TimeSpan timeout)
{
   try
   {
      queue.Peek(timeout);
   }
   catch(MessageQueueException ex)
   {
      if (e.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
      {
         if (messageAvailable)
         {
            msg = SecondaryMessageSource();
         }

      }

      throw;
   }

   msg = queue.Receive();
}

MSMQ 没有提供检查队列上消息计数的机制。确定消息是否可用的唯一方法是使用 Peek。如果发生 MessageQueueException 并将其错误设置为 IOTimeout,则 Peek 已超时并且队列中没有可用消息。

该例程将在一个线程的循环中调用,该线程的唯一目的是检索消息。超时将在毫秒范围内。调用堆栈由单个方法组成,线程不负责其他任何操作。我知道该方法会不断抛出异常,这被认为是不好的做法,但在这种情况下,真的有那么糟糕吗?如果是这样,是否有人对如何在不使代码变得完全复杂的情况下完成此任务有任何建议?

4

3 回答 3

2

由于您的程序逻辑(检查一个队列,如果没有消息,则检查另一个)以及 MSMQ 的工作方式,您将不得不处理异常。但是,我觉得可能有一种比在 catch 子句中包含该代码更优雅的方法。

这是我要做的:

private const int ReceiveTimeout = xxxx;

private bool TryReceiveMessage(MessageQueue queue, out Message message)
{   
    try
    {
        message = queue.Receive(ReceiveTimeout);

        // if we made it here, we are good and have a message
        return true;
    }
    catch(MessageQueueException ex)
    {
        if (MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
        {
             // this is not exceptional to us, so just return false
             return false;
        }

        // Throw anything else as it is unexpected
        throw;
    }    
}

然后,我会这样编写您的调用方法:

private Message MyMethodThatIsCalledInALoop()
{
   // These could also be params, etc.
   MessageQueue primary = // whatever code to get a reference to your primary queue
   MessageQueue secondary = // whatever code to get a reference to your secondary queue

   Message message = null;

   if (TryReceiveMessage(primary, out message))
   {
       return message;
   }

   if (TryReceiveMessage(secondary, out message))
   {
       return message;
   }

   // this would still be null
   return message;
}
于 2013-05-13T12:11:18.313 回答
0

MSMQ 没有提供检查队列上消息计数的机制。确定消息是否可用的唯一方法是使用 Peek。如果发生 MessageQueueException 并将其错误设置为 IOTimeout,则 Peek 已超时并且队列中没有可用消息

你自己回答了。由于没有其他方法可以做到,您有什么选择?

于 2013-05-13T11:27:22.710 回答
0

您应该为每个轮询作业创建 2 个单独的线程,并将它们的消息存储在同步队列中,以便主线程可以对它们进行排序并从那里获取适当的消息。这样您就可以在Peek调用上设置“无限”超时。

于 2013-05-13T11:28:17.027 回答