1

I know that you shouldn't use exceptions for non-exceptional conditions, but I wanted to run this past others to see if what I'd like to do is really that bad.

I have a routine that is attempting to get a message off of a MSMQ message queue. If no messages is available on the queue, it checks a secondary source to see if a message is available there. An example of the routine follows:

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 provides no mechanism for checking the count of messages on the queue. The only way to determine if a message is available is by using Peek. If a MessageQueueException occurs with its error set to IOTimeout, then the Peek has timed out and no message is available on the queue.

This routine will be called within a loop on a thread whose sole purpose is to retrieve messages. The timeout will be in the millisecond range. The call stack consists of a single method, and the thread is responsible for doing nothing else. I know that the method will be constantly throwing exceptions, which is considered bad practice, but in this case is it really all that bad? If so, does anyone have any suggestions on how to accomplish this task without the code becoming totally convoluted?

1
  • 2
    What would be the alternative to using Peek? Commented May 13, 2013 at 11:26

3 Answers 3

2

Because of your program logic (check one queue and if no messages, check the other) and because of the way MSMQ works, you are going to have to deal with the exceptions. However, I feel there is probably a more elegant way to do it than have that code in your catch clause.

Here's what I would do:

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;
    }    
}

Then, I would code your calling method as such:

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;
}
Sign up to request clarification or add additional context in comments.

Comments

0

MSMQ provides no mechanism for checking the count of messages on the queue. The only way to determine if a message is available is by using Peek. If a MessageQueueException occurs with its error set to IOTimeout, then the Peek has timed out and no message is available on the queue

You answered it yourself. As there is no other way to do it, what choice do you have?

3 Comments

It's an XY issue methinks. The intended solution can only be implemented in an ugly way, but there might be more solutions to the real problem.
He states that the other queue is a secondary source. i.e. a fail over.
Well if that means the second queue must not be read unless the first fails, the exception solution is the only correct one. He didn't specify that explicitly though.
0

You should make 2 separate threads for each of the polling jobs, and have them store their messages in a synchronized queue so the master thread can sort through them and get the appropriate ones from there. This way you can just set 'infinite' timeouts on the Peek calls.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.