Reconnecting to a remote MessageQueue when it has to reboot

  • Thread starter Thread starter felecha
  • Start date Start date
F

felecha

I have a VB.Net application that runs as a Windows Service and
monitors a MessageQueue on another machine. At times that machine
will have to be rebooted, so I've been working on how to get my
Service to re-establish the connection after the remote machine is
back.

I found that as soon as the remote machine goes down, the
BeginReceive() method and the ReceiveCompleted() event handler start
throwing an exception, for QueueNotAvailable, which is very
reasonable. I figured I would catch the exception, tell the
CurrentThread to sleep for, say, 5 seconds, then instantiate the
MessageQueue object again, set its Formatter, add the handler, and
call BeginReceive again. I thought it should continue throwing the
same exception and reinstantiating itself until the remote
MessageQueue is on again.

But now I find that after the new MessageQueue is up (which I can see
in my debugging log) the EndReceive() method called inside the
ReceiveCompleted() throws another exception - "An invalid handle
was passed to the function." I thought maybe the new MessageQueue
instance was null or somehow not right, but I've put debug lines in
to check the MessageQueue properties and the properties of the
AsyncResult passed to EndReceive(), and they are all non-null, so I
figure that's not the problem.

Any clues?
 
I found there's apparently a cache for handles, so I called
ClearConnectionCache() before reinstantiating the MessageQueue
object, but then the next call to BeginReceive() threw an exception
saying "Remote computer not available" as if the connection cache
stored EVERYTHING needed, not just handles but remote machine name.

So it'g getting to be a circular problem.

By the way, in case it's not clear:

The remote machine has a private Queue on it, that messages from that
machine's processes send messages to. My app is on this machine, and
instantiates a
MessageQueue(name_of_that_private_queue_on_the_remote_machine).
 
I found a property I didn't notice before, MessageQueue.ReadHandle, so
I added a debug line that wrote the value to a log, and it looks like
even when I call for a New() MessageQueue, the handle remains the
same as when the whole Service starts up. So it looks like the
caching thing is holding on to a handle that is probably the cause of
the invalid handle exception when the remote queue starts up again.

I can't find any way, though, to find out what the new handle needs to
be to allow a valid call to EndReceive(). When I tried
ClearConnectionCache (and another time I set EnableConnectionCache to
False to try that) the result was the not even the BeginReceive()
method could work.

I'm really stumped.
 
felecha,
I've just started using MSMQ, so I don't have all the specifics.

Are you working with a public or private queue? I was under the impression
that MSMQ will hide the fact that a remote public queue is not available
from you.

Have you tried asking in one of the MSMQ specific newsgroups?

microsoft.public.msmq.*

Hope this helps
Jay

felecha said:
I have a VB.Net application that runs as a Windows Service and
monitors a MessageQueue on another machine. At times that machine
will have to be rebooted, so I've been working on how to get my
Service to re-establish the connection after the remote machine is
back.

I found that as soon as the remote machine goes down, the
BeginReceive() method and the ReceiveCompleted() event handler start
throwing an exception, for QueueNotAvailable, which is very
reasonable. I figured I would catch the exception, tell the
CurrentThread to sleep for, say, 5 seconds, then instantiate the
MessageQueue object again, set its Formatter, add the handler, and
call BeginReceive again. I thought it should continue throwing the
same exception and reinstantiating itself until the remote
MessageQueue is on again.

But now I find that after the new MessageQueue is up (which I can see
in my debugging log) the EndReceive() method called inside the
ReceiveCompleted() throws another exception - "An invalid handle
was passed to the function." I thought maybe the new MessageQueue
instance was null or somehow not right, but I've put debug lines in
to check the MessageQueue properties and the properties of the
AsyncResult passed to EndReceive(), and they are all non-null, so I
figure that's not the problem.

Any clues?
 
It's a private queue on a remote machine.

The system we're building is an alerting system. When there's a
disaster, first-responders are alerted and a conferencing system goes
into action. The main control system resides on a host that has no
human interface, but runs on Windows XP Pro. That's where the Queue
is located, on that remote machine. The host communicates with the
human-interfacing software through that queue. I'm writing the
Administration Station application that will be on a regular desktop.
the Admin person can change configuration for the system and then
have the system reset itself. It's during the reset that the Queue
goes down. When it finishes its reset, I need to be able to get back
to receiving messages from the host queue.

How do I get to that newsgroup? I tried just using the links I found
to it, but they go nowhere. I generally use Opera as a browser, and
it says Server not found. IE6 tells me I need to install newsreader
software. I don't know about that.
 
felecha,
It's a private queue on a remote machine.
I suspect this may be the issue, however I only open private queues on the
local machine...
How do I get to that newsgroup? I tried just using the links I found
to it, but they go nowhere. I generally use Opera as a browser, and
it says Server not found. IE6 tells me I need to install newsreader
software. I don't know about that.
How are you accessing this group?

Remember I gave you the root of a number of groups...

Here is the list on Google:

http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&group=microsoft.public.msmq

I would think either:
microsoft.public.msmq.networking
microsoft.public.msmq.programming
microsoft.public.msmq.setup

Can answer your question.

Hope this helps
Jay

felecha said:
It's a private queue on a remote machine.

The system we're building is an alerting system. When there's a
disaster, first-responders are alerted and a conferencing system goes
into action. The main control system resides on a host that has no
human interface, but runs on Windows XP Pro. That's where the Queue
is located, on that remote machine. The host communicates with the
human-interfacing software through that queue. I'm writing the
Administration Station application that will be on a regular desktop.
the Admin person can change configuration for the system and then
have the system reset itself. It's during the reset that the Queue
goes down. When it finishes its reset, I need to be able to get back
to receiving messages from the host queue.

How do I get to that newsgroup? I tried just using the links I found
to it, but they go nowhere. I generally use Opera as a browser, and
it says Server not found. IE6 tells me I need to install newsreader
software. I don't know about that.
 
Well I have stuff to learn still, I guess. I was able to get to the
groups directly through the google link, but earlier attempts gave
messages saying I needed newsreader software, which I don't know
about.

Anyway, I did see a post at one of the groups that led me to
msmqfaq.doc, where I found something that pretty much confirms me in
my conclusion about my problem. The items says:

4. An attempt to read from a remote queue fails with error
“invalid-handle.” Why?
This probably occurred because the remote computer has restarted, and
you use a cached queue handle that is no longer valid.
In core MSMQ, a local application uses a handle of the local MSMQ
service when reading from a remote queue, and the local MSMQ service
in turn has a remote queue handle from the remote computer. If the
remote computer restarts, the remote queue handle used by the local
MSMQ service is no longer valid. The standard workaround for this is
to close and reopen the queue. However, by default this workaround
does not work in the Microsoft .NET Framework, and the Close method
of the MessageQueue object does not close the queue handle. This is
because the .NET Framework uses a connections cache that caches queue
handles. To close a queue handle, either disable the connections
cache, or call ClearConnectionCache.

Well, it looks like the cache is the issue, but ... I already tried
disabling and clearing, and both steps led to other exceptions being
thrown.

Last night I tried another idea -- in the catch for the exception when
the remote queue goes down, I send an MSMQ Message to a LOCAL queue
that I set up, with a second little app running that has a
MessageQueue object that listens to THAT queue, and simply calls
ServiceController.Stop and ServiceController.Start on my Service, in
effect "rebooting" my Service in response to the reboot of the remote
machine. It keeps rebooting the Service every 5 seconds until the
remote queue comes up and then the connection is established and we
go on just fine.

It works consistently so far, but I still hope I can solve the cache
problem internally in the Service somehow. Creating apps to control
other apps bothers me.
 
Back
Top