JMS, time-to-live and Websphere MQ
October 9, 2008 3 Comments
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:
While in the standalone JVM:
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.