JMS, time-to-live and Websphere MQ

Without long-winded introduction… I had a problem setting message expiration using JMS and Websphere MQ as an underlying JMS provider. As you may (not) know there is a big difference if you set time to live on QueueSender (which should work) or JMS expiration on the message (which is actually ignored before you send the message and specified so). I used JMS to send a request and waited for response in the same method subsequently. Because the reply is received in a synchronous manner and after timeout it’s not processed it’s good idea to set time to live on the request.

I expect you know JMS so the following code excerpts are not complete compilable examples. Client has some initialization code:

queueConnection = queueConnectionFactory
  .createQueueConnection("mqm", "mqm");
queueSession = queueConnection
  .createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueSender = queueSession
  .createSender(requestQueue);

Request queue is looked up in the JNDI – in my case it was the LDAP with following object for the queue (LDIF):

dn: cn=request.q, ...
objectClass: javaContainer
objectClass: javaObject
objectClass: javaNamingReference
objectClass: top
javaReferenceAddress: #0#VER#1
javaReferenceAddress: #1#DESC#Request Q
javaReferenceAddress: #2#EXP#0
javaReferenceAddress: #3#PRI#-1
javaReferenceAddress: #4#PER#-1
javaReferenceAddress: #5#CCS#1250
javaReferenceAddress: #6#TC#1
javaReferenceAddress: #7#ENC#273
javaReferenceAddress: #8#QU#SERVICE_REQ
javaReferenceAddress: #9#QMGR#
javaClassName: com.ibm.mq.jms.MQQueue
javaFactory: com.ibm.mq.jms.MQQueueFactory
cn: request.q

Message is sent in the following code:

queueSender.setTimeToLive(MAX_RETAIL_TIMEOUT / 2);
queueSender.getTimeToLive();
queueSender.send(jmsMsg);
jmsMsg.getJMSExpiration();

The trouble is that while getTimeToLive really returns some number (in ms), getJMSExpiration that should return the timestamp when the message expires returns zero instead. And really – the message never expires. Something is wrong when sender claims the time-to-live is set but it actually is not. It was funny to find out that the same code works perfectly fine in EJB container – getJMSExpiration returns real timestamp and the message is removed from the queue as expected. It took me some time to find out the difference in the debug process.

QueueSender in application server (Glassfish was used) is implemented by the com.sun.genericra.outbound.MessageProducerProxy and this object holds actual com.ibm.mq.jms.MQQueueSender while in outside of the container there is no genericjmsra proxy in the way – but this wasn’t the problem. IBM’s class holds something called queueSpec. In appserver it was:

queue:///SERVICE_REQ?targetClient=1

While in the standalone JVM:

queue:///SERVICE_REQ?expiry=0&priority=-1&persistence=-1&CCSID=1250&targetClient=1

I was suddenly very suspicious whether parameters in that URL don’t override my programmatic settings on the queue sender. And where they come from? Yeah, you can guess – they are part of the queue object reference in the LDAP. Queue for appserver was stored in its JNDI and it was configured some other way. So I tried to modify my LDAP object to remove values with EXP (and some other along the way) of the attribute javaReferenceAddress:

dn: cn=reqest.q, ...
objectClass: javaContainer
objectClass: javaObject
objectClass: javaNamingReference
objectClass: top
javaReferenceAddress: #0#VER#1
javaReferenceAddress: #1#DESC#Request Q
javaReferenceAddress: #2#PER#-1
javaReferenceAddress: #3#CCS#1250
javaReferenceAddress: #4#TC#1
javaReferenceAddress: #5#QU#SERVICE_REQ
javaReferenceAddress: #6#QMGR#
javaFactory: com.ibm.mq.jms.MQQueueFactory
javaClassName: com.ibm.mq.jms.MQQueue
cn: request.q

Yup, my code started to work. In case you want some command to check the Websphere MQ as well, you can try this one from samples (here on Solaris, should work on other UNIX too):

$ cd /opt/mqm/samp/bin
$ ./amqsbcg AS4_DOMPAY_REQ

AMQSBCG0 - starts here
**********************

  MQOPEN - 'AS4_DOMPAY_REQ'

  MQGET of message number 1

****Message descriptor****
  StrucId  : 'MD  '  Version : 2
  Report   : 0  MsgType : 1
  Expiry   : 15  Feedback : 0

… the rest is not important

Expiry value -1 means “never expire”. This message also disappeared after another few seconds. That was what I wanted. What is the point behind my unlucky LDAP configuration? First – I don’t know if it’s correct when queue sender returns some time-to-live but it actually doesn’t work in the end. I don’t know how this works with other JMS providers. I don’t care. I just googled the whole damned Internet to finally get to the result on my own. If you have searched for the problem, found this and it would helped, be my guest.

Advertisements

About virgo47
Java Developer by profession in the first place. Gamer and amateur musician. And father too. Naive believer in brighter future. Step by step.

3 Responses to JMS, time-to-live and Websphere MQ

  1. T.Rob says:

    When you were Googling around, did you find IBM’s WebSphere MQ Using Java manual?

    The values available for the Expiry property are App, Unlimited or any positive integer. I believe these translate to -1, 0 and >0 respectively. This allows expiration to be enforced in the managed object definition or delegated to the application code.

    There are many instances where this is useful. One of my clients had tuned their network for non-persistent messages and as part of a code change message persistence was enabled for a high-volume application causing significant degradation of the network. This client updated the JNDI definition to enforce non-persistence and the problem went away.

    Both persistence and expiry may be enforced in the object definition or delegated to the application. The advice often given is that these should be set in the app if the value needs to change at run time, otherwise set it in the managed object to insure the business requirement is met consistently.

    As to the question of what should be returned if you try to set it and it’s overridden…I’ll agree that returning an apparently correct value is not intuitive. I would have expected it to return the actual value used.

    — T.Rob

  2. virgo47 says:

    Thank you for your comment. If I understand it correctly, if I had had -1 in that property, my code would have worked, is that right? I’m aware of that manual and I’ve read some parts. Trouble here is that no one really can read the whole thing from the start to the end just to find this subtle information and I felt like message sender is lying to me. 🙂 I appreciate your post because I’m always hungry for pieces making the picture more complete and now I see that there might be a pretty good reason why it works like it works. Code examples for time-to-live are mostly on different places than the JNDI binding explanation – important thing for me was to realize that “stuff in LDAP is wrong!” in the first place. Thank you for providing additional information to my story.

  3. T.Rob says:

    “If I understand it correctly, if I had had -1 in that property, my code would have worked, is that right?”

    I believe that is true. I have not looked to see what numeric values the symbolic names map to but at least one of them causes the value in your code to be honored and I think it maps to -1.

    I agree about wading through the manuals. It can seem like walking through quicksand! On the other hand, WMQ has one of the most comprehensive manual sets around so the answer is usually in there if you search long enough. I’ve developed a love/hate relationship with the WMQ docs over the years because of this.

    Before you tear your hair out or lose too much sleep over your next WMQ issue, please go to either http://mqseries.net or to the Vienna WMQ Listserv and post a query. One of the best things about WMQ is the very active and knowledgeable communities of users supporting it and each other. Once you get plugged into one of these communities, the bulk of your WMQ questions are answered quickly and accurately. Both communities are free to join and post and both have archives searchable anonymously.

    Best regards,
    — T.Rob

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s