tags:

views:

1357

answers:

5

What would be a nice and good way to temporarily disable a message listener? The problem I want to solve is:

  • A JMS message is received by a message listener
  • I get an error when trying to process the message.
  • I wait for my system to get ready again to be able to process the message.
  • Until my system is ready, I don't want any more messages, so...
  • ...I want to disable the message listener.
  • My system is ready for processing again.
  • The failed message gets processed, and the JMS message gets acknowledged.
  • Enable the message listener again.

Right now, I'm using Sun App Server. I disabled the message listener by setting it to null in the MessageConsumer, and enabled it again using setMessageListener(myOldMessageListener), but after this I don't get any more messages.

A: 

That looks to me like the messages are being delivered but nothing is happening with them because you have no listener attached. It's been a while since I've done anything with JMS but don't you want to have the message sent to the dead letter queue or something while you fix the system, and then move the messages back onto the original queue once you're ready for processing again?

MrWiggles
That might be what happens. Unfortunately, I don't have that control of the jms server, all I can do is to specify a queue to get messages from, no dead letter queue. I guess I could stop the QueueConnection, but that can't be done from the messagelistener thread.
davidi
How come you don't have access to the JMS server. As duffymo has rightly pointed out, its the error queue you want access to. Otherwise you're going to end up replicating behaviour in code that the JMS server provides for you
MrWiggles
I do have that access to the JMS server...in my development environment, but I cannot expect that the users of the application I'm working on (a bridge between two messaging systems) have the same permissions to the JMS server. Is that dead letter queue the usual way to deal with these problems?
davidi
A: 

On WebLogic you can set up max retries, an error queue to handle messages that exceed the max retry limit, and other parameters. I'm not certain off the top of my head, but you also might be able to specify a wait period. All this is available to you in the admin console. I'd look at the admin for the JMS provider you've got and see if it can do something similar.

duffymo
A: 

Problem solved by a workaround replacing the message listener by a receive() loop, but I'm still interested in how to disable a message listener and enable it shortly again.

davidi
+5  A: 

How about if you don't return from the onMessage() listener method until your system is ready to process messages again? That'll prevent JMS from delivering another message on that consumer.

That's the async equivalent of not calling receive() in a synchronous case.

There's no multi-threading for a given JMS session, so the pipeline of messages is held up until the onMessage() method returns.

I'm not familiar with the implications of dynamically calling setMessageListener(). The javadoc says there's undefined behavior if called "when messages are being consumed by an existing listener or sync consumer". If you're calling from within onMessage(), it sounds like you're hitting that undefined case.

There are start/stop methods at the Connection level, if that's not too coarse-grained for you.

John M
Oh, it really was that simple. I expected more threads to call the onMessage method. Thanks a bunch!
davidi
Connections are thread-safe. Sessions on down (sessions, consumers, producers) are not thread-safe. Your code needs to avoid multithreaded access. To enforce that, JMS couldn't multithread listener calls on one consumer.
John M
I just noticed that the JMS spec explicitly specifies this serial delivery behavior. It's section 4.4.16 of the JMS 1.0.2 spec. In the past I thought it was just implied by the threading rules.
John M
A: 

In JBoss the following code will do the trick:

   MBeanServer mbeanServer = MBeanServerLocator.locateJBoss();
    ObjectName objName = new ObjectName("jboss.j2ee:ear=MessageGateway.ear,jar=MessageGateway-EJB.jar,name=MessageSenderMDB,service=EJB3");
    JMSContainerInvokerMBean invoker = (JMSContainerInvokerMBean) MBeanProxy.get(JMSContainerInvokerMBean.class, objName, mbeanServer);

    invoker.stop(); //Stop MDB
    invoker.start(); //Start MDB
Jeremy