Tips for a successful MSMQ-enabled application

For the past few weeks I've been deep down inside a client's project. It's a large distributed application and one of the features I was working on made me realize just how little I've gotten the chance to use MSMQ in my projects, which is a total shame, really.
MSMQ (Microsoft Message Queue) is a great bridge for helping you distribute messages between applications in an asynchronous manner (kinda like email). The syntax for using MSMQ is pretty easy (a couple of lines to send a message to a queue in the simplest form) and the benefits are huge if you need asynchronous conversations between your disconnected application components.
 
However.
 
MSMQ, like many other products and components, has its dark corners, as I've found during the past couple of weeks. I'll list them here so that I (and you) don't lose track of them. Some of them I've gotten straight off Yoel Arnon - MSMQ Guru and once part of the original MSMQ Team at Microsoft. You can read his blog over here(guess what its about..).
 
  1. The problems with remote queues and COM+ transactions
I had quite a simple scenario laid out for me. Get some info from a remote queue and try to insert it into a database. If the database insert fails, rollback the "get" from the queue as well so that the info stays queued for the next time around to be inserted into the DB again. Easy enough I tried to open a new transaction context using COM+ before calling "receive" from the queue and abort it if the DB failed. My integration tests (driven by NUnit) showed that even though Rollback was called, the message did not return into the queue. Weird because this was a transactional Queue and that should have worked. After asking Yoel it turns out that the fact that this queue was remote(residing on a different computer) meant that you couldn't actually do that. Remote queues do not support a transactional receive inside a transaction. If the queue had been local (on the local machine) this would have worked. "Send" does work in both ways, but receive is somehow special. There are ways around it, detailed here, but I've managed to get around it by doing the following:
Create a local, private queue(cannot be used from remote machines) which acts as a transactional queue cache. The receive from the remote queue is actually a two-phase receive: get the info from the remote queue and put it into the local cache queue. Then do all your transactional work using the local queue. That guarantees that you never lose a message if you need to rollback on multiple actions.
 
2. CanSend and CanRecieve = damn lies
If your remote queue tells you that you can't sent or can't receive using its public boolean properties- don't trust it. It might be wrong. That's just how it is.
 
3. Make sure you have the right permissions
On windows Server 2003 in order to receive from a remote queue you need to explicitly go to the queue permissions page, click on the "Anonymous Logon" role and add the "Receive" ability to it, or you won't be able to receive from the remote queue
 
It took me several hours to capture these important insights - so now you don't have to. If you have any more "Watch out for" tips on MSMQ - feel free to post a comment to this post.
Good luck!
Published Monday, August 22, 2005 4:02 AM by RoyOsherove
Filed under:

Comments

Monday, August 22, 2005 6:34 AM by ilan

# re: Tips for a successful MSMQ-enabled application

Oops, sorry, I sent the previous message before I finished it by mistake.
Let's recapitulate:

Well, what I'm about to detail is not really a problem, but something you should be aware of.
If you read the messages from the Q using BeginReceive, you may end up receiving one more message than you intended. Imagine you are using the following scheme:
void init()
{
queue.ReceiveCompleted += new ReceiveCompletedEventHandler(receiveCompleted);
queue.BeginReceive();
}
void receiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
MessageQueue sourceQueue = sender as MessageQueue;
Message msg = sourceQueue.EndReceive(e.AsyncResult);
// Do something with the message
sourceQueue.BeginReceive();
}
void stopReceivingMessages()
{
queue.ReceiveCompleted -= new ReceiveCompletedEventHandler(receiveCompleted);
}
Well, after the call to stopReceivingMessages() there is still one message you will get (unless you close the Q of course)...
Tuesday, August 23, 2005 11:54 PM by John Cavnar-Johnson

# re: Tips for a successful MSMQ-enabled application

There's an important principle to follow in developing MSMQ applications: Send to remote queues, receive from local queues.
Monday, September 12, 2005 2:02 AM by Dilip M

# re: Tips for a successful MSMQ-enabled application

Unfortunately, the 'receive from local queues' is not always possible. We are building a smart client app with the users being disconnected most of the time.
And we don't want to use AD for routing so I don't see any options but to use remote queues for reads. If there is any better way to approach this, I'd be interested to know.
Also curious as to whether it makes a significant difference in having multiple (not shared by huge # of users) queues or one queue where all remote users peek and pull off messages.
Friday, December 08, 2006 2:29 PM by Marcus

# re: Tips for a successful MSMQ-enabled application

"Anonymous Logon" role!!! Thanks Roy...