All the que messages are sent to que1 server and we have 2
queue listeners setup, one on que1, another on que2. We
logged all the activities inside component to a sql table,
for a few hours, all the que jobs failed and the sql log
table filled with the above error/info. And the log table
even filled with the errors when nobody submits any jobs.
It didn't get back to normal until we rebooted que1. Can
somebody please explain what happened and how to prevent
it happening in the future? thanks.
Your receiving programs must be calling MQReceiveMessage passing in a
cursor handle as the seventh parameter (i.e., not passing NULL at that
parameter). Cursor handles are used to keep track of where you are in
the queue and where the next receive will happen.
The problem is that if you have more than one program removing messages
from a queue, then one program can remove the message that the other
program's cursor points to. When that happens you get the error
MQ_ERROR_MESSAGE_ALREADY_RECEIVED (0xC00E001D).
For example, see this description of receiving with two cursors
http://msdn.microsoft.com/library/en-us/msmq/msmq_about_queues_3ugj.aspp
At the third stage, cursor1 and cursor2 (which could belong to different
programs) both point at message C. Cursor1 is used to retrieve message
C so cursor 1 is advanced to the next message in the queue (message D).
Cursor 2 still points where message C had been, but now there isn't a
message there. So, when the program using cursor 2 attempts to call
MQReceiveMessage passing in cursor 2, that receive will fail with the
error you are seeing.
Since that receive fails with an error, cursor 2 remains pointing where
message C had been, so any subsequent attempt to perform a receive using
cursor 2 will also fail with the same error message. When you get a
0xC00E001D error, you must re-initialise the cursor before using it
again. For example, you could use MQ_PEEK_NEXT to move the cursor to
the next message in the queue.
Since you have two programs both removing messages from the same queue,
it would be better if you didn't use cursors and just had each program
remove the top message from the queue every time it needed a message.
That way you'll avoid these kinds of problems where two cursors end up
pointing at the same message. If your application architecture really
needs cursors to work correctly then you need to code for the case where
the cursors collide and re-initialise the broken cursor in some
appropriate fashion.