How to Get message count in a durable subscriber in IBM MQ? - ibm-mq

I am using a default IBM mq topic 'dev/' and have a durable subscriber attached to this topic.
Using a JMS Producer client if I produce some message but do not consume them, they are held in the subscription for the durable client.
So I want to check the message count for that subscription using MQSC Command, I'm able to check it using MQ Explorer in the status of the subscription, but want to check it via command line, using MQSC. So far I've got
DISPLAY SUB('JMS:QM1:LOCALDB.vanshaj.pump_fs_ns_Pump:LOCALDB.vanshaj.pump_fs_ns_Pump') ALL
but this only displays the following property
AMQ8096I: IBM MQ subscription inquired.
SUBID(414D5120514D31202020202020202020CDBBF261053D4321)
SUB(JMS:QM1:LOCALDB.vanshaj.pump_fs_ns_Pump:LOCALDB.vanshaj.pump_fs_ns_Pump)
TOPICSTR(dev/) TOPICOBJ( )
DISTYPE(RESOLVED)
DEST(SYSTEM.MANAGED.DURABLE.61F2BBCD21433D04)
DESTQMGR(QM1) PUBAPPID( )
SELECTOR( ) SELTYPE(NONE)
USERDATA( )
PUBACCT(0000000000000000000000000000000000000000000000000000000000000000)
DESTCORL(414D5120514D31202020202020202020CDBBF261053D4321)
DESTCLAS(MANAGED) DURABLE(YES)
EXPIRY(UNLIMITED) PSPROP(MSGPROP)
PUBPRTY(ASPUB) REQONLY(NO)
SUBSCOPE(ALL) SUBLEVEL(1)
SUBTYPE(API) VARUSER(ANY)
WSCHEMA(TOPIC) SUBUSER(app)
CRDATE(2022-01-28) CRTIME(12:11:30)
ALTDATE(2022-01-28) ALTTIME(12:14:14)
what I need is the message count which can be seen in the below image

IBM MQ subscriptions are each associated with a queue that is used to hold the messages. The queue is displayed in the DEST field of the subscription. In your example the queue name is SYSTEM.MANAGED.DURABLE.61F2BBCD21433D04.
If you want to view the count of unconsumed messages you will need to display the CURDEPTH of the queue associated with the subscription, for example:
DIS QLOCAL(SYSTEM.MANAGED.DURABLE.61F2BBCD21433D04) CURDEPTH
The output will look something like this:
AMQ8409I: Display Queue details.
QUEUE(SYSTEM.MANAGED.DURABLE.61F2BBCD21433D04)
TYPE(QLOCAL) CURDEPTH(128)
IBM MQ managed subscriptions (all JMS subscriptions are manged since you are unable to specify your own queue to use) will have name in the following format:
For nondurable subscriptions:
SYSTEM.MANAGED.NDURABLE.*
For durable subscriptions:
SYSTEM.MANAGED.DURABLE.*
If you are interested in all managed subscriptions with unconsumed messages you can use this command:
DIS QLOCAL(SYSTEM.MANAGED.*) WHERE(CURDEPTH GT 0)

There are two commands to look at subscriptions, similar to many other IBM MQ resources.
DISPLAY SUB
to look at the static configuration.
DISPLAY SBSTATUS
to look at the live run-time status numbers.
It is in this latter command that you will find the Subscription Status details that you have shown in your screenshot.
AMQ8099I: IBM MQ subscription status inquired.
SUB(ABC.1)
SUBID(414D51204D51473120202020202020207E20475E2237A83F)
SUBUSER(mqgusr1) RESMDATE( )
RESMTIME( ) LMSGDATE( )
LMSGTIME( )
ACTCONN(000000000000000000000000000000000000000000000000)
DURABLE(YES) MCASTREL( , )
NUMMSGS(0) SUBTYPE(ADMIN)
TOPICSTR(xx/yy/zz)
If you want to see how many messages have been delivered to the subscriber, but have not yet been consumed by the application, then you should issue the following command against the queue name listed in the DISPLAY SUB() DEST attribute.
DISPLAY QLOCAL(SYSTEM.MANAGED.DURABLE.61F2BBCD21433D04) CURDEPTH

Related

JMSListener escapes '.' for durable subscriptions

With Spring JMS 4.3.19 as well as with 5.2.5 I am trying to set up a JMSListener for durable subscriptions:
#JmsListener(destination = "test", subscription = "Consumer.Test", connectionFactory = "factory")
public void receiveFromDurableSub(String message) {
System.out.println("receiveFromTest: " + message);
}
But it ends up in Consumer\\.Test. For addresses it works somehow.
How can I avoid those backslashes?
JMS topic subscriptions are implemented on ActiveMQ Artemis as queues. Each subscription gets it own queue.
The name of the queue depends on how the subscription is configured. The broker will take the JMS client ID (if one is configured), the JMS subscription name (if one is configured), and the JMS subscription's durability to construct the name of the underlying subscription queue. The broker uses the . character to concatenate all these piece of information together to compose the final name. See the related source code for more details on that bit.
In order to be able to decompose this name into its constituent parts later any uses of the . character in the client ID or subscription name have to be escaped.
Since you're using Consumer.Test for the JMS subscription's name this will ultimately be escaped to Consumer\\.Test for use in the underlying subscription queue's name. The broker's use of the . character is not configurable in this case.
If you don't want your subscription's name to be escaped then I recommend you don't use a name with a . character in it (e.g. Consumer-Test).

Overlapping MQ Cluster and reply message delivery with IBM MQ

I have two clusters CLUSMES and CLUSHUBS. Each cluster has two queue managers.
Cluster CLUSMES has QMGRS: QMGR1A and QMGR1B
Cluster CLUSHUBS has QMGRS: QMGR3A and QMGR3B
There is a Gateway QMGR: QMGR2, which forms the overlap and is a partial repository in each MQ cluster.
Request messages are sent out from either QMGR1A/B to either QMGR3A/B via QMGR2 which acts as a cluster Load balance to QMGR3A/B (This works fine) and a reply is expected back to the sending QMGR.
All channel connectivity is in place and fully functional. The problem is how to return the message from where it came from. The replying QMGR connects to QMGR3A/B and issues a put. I will either get a REMOTE_QMGR not found (MQRC 2087) or a MQ Object not found (MQRC 2085) depending on how I have it configured. The message header of the message contains the ReplytoQueue and ReplyToQMgr properly. I would like to have the replying application just issue a put and have it delivered to the proper queue in CLUSMES, but this is proving to be extremely difficult. I have played with Remote QMGR Alias and QAlias on the GateWay Qmgr: QMGR2, but no luck. There is got to be a simple trick to this and there are plenty of examples, but I have not been able to implement one successfully. A clear cut example of what my return path should be would be most helpful. Keep in mind, that the ReplyToQMgris in the MQMD and resolution needs to occur from that. I need resolution to occur at the QMGR2 level, where both clusters are known. Concrete full suggestions appreciated.
MQ Definitions on the QMGR1A/B, where the REPLY is expected:
DEFINE QLOCAL('SERVER.REPLYQ') CLUSTER('CLUSMES')
On QMGR2 ( The Gateway for message hoping)
DEFINE NAMELIST(CLUSTEST) NAMES(CLUSMES,CLUSHUBS)
DEFINE QALIAS(SERVER.ALIAS.REPLYQ) TARGQ(SERVER.REPLYQ) CLUSTER(CLUSTEST) DEFBIND(NOTFIXED)
DEFINE QREMOTE(QMGR1A) RNAME(' ') RQMNAME(QMGR1A) XMITQ('') CLUSTER(CLUSHUBS)
DEFINE QREMOTE(QMGR1B) RNAME(' ') RQMNAME(QMGR1B) XMITQ('') CLUSTER(CLUSHUBS)
On MQMGR3A/B QALIAS(SERVER.ALIAS.REPLYQ) cluster queue. The Gateway QMGR could not resolve the baseQ: mqrc_unknown_alias_base_q 2082
This was the configuration when trying to resolve it using the cluster.
When the request message is sent by the application it would specify ReplyToQMgr of either QMGR1A and QMGR1B and ReplytoQueue with the name of the queue that is present on QMGR1A and QMGR1B, the reply queue need not be clustered.
On gateway queue manager QMGR2 you would define the following objects:
DEFINE QREMOTE(QMGR1A) RNAME('') RQMNAME(QMGR1A) XMITQ('') CLUSTER(CLUSHUBS)
DEFINE QREMOTE(QMGR1B) RNAME('') RQMNAME(QMGR1B) XMITQ('') CLUSTER(CLUSHUBS)
This would allows any queue manager in the cluster CLUSHUBS to route reply messages back to QMGR1A and QMGR1B via gateway queue manager QMGR2.
If you want to limit queues on QMGR1A and QMGR1B that queue managers in the CLUSHUBS cluster can put to you would need to take a different approach. Let me know if that is what you need and I will update my answer with some suggestions.

message-driven-channel-adapter: Polling false/phantom messages from queue

We are using spring integration and daily in our logs we can see below stacktrace. Other JMS adapters are working fine, we think only below one is missing something:
Spring integration configuration:
<jms:message-driven-channel-adapter concurrent-consumers="1" id="jmsInLOAN" destination="queueLOAN" channel="LOANCommonDataChannel" acknowledge="transacted" />
Please find below MQ statistics of Put and Msgs read count, there should be exact count of Message read by adapter. I am worried about spring integration's message-driven-channel-adapter of reading extra messages from queue. Any help would be appreciated.
WARN 07/Jan/2016 09:04:15,438 [org.springframework.jms.listener.DefaultMessageListenerContainer#23-1] springframework.jms.listener.DefaultMessageListenerContainer - [SYSTEM_ID=HBUSLOANIQ] [MESSAGE_ID=null] Execution of JMS message listener failed, and no ErrorHandler has been set.
org.springframework.integration.MessagingException: unsupported payload type [com.ibm.jms.JMSMessage]
at org.springframework.integration.xml.DefaultXmlPayloadConverter.convertToDocument(DefaultXmlPayloadConverter.java:76)
at org.springframework.integration.xml.DefaultXmlPayloadConverter.convertToNode(DefaultXmlPayloadConverter.java:88)
at org.springframework.integration.xml.router.XPathRouter.getChannelIdentifiers(XPathRouter.java:119)
at org.springframework.integration.router.AbstractMessageRouter.determineTargetChannels(AbstractMessageRouter.java:247)
at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:211)
It looks like you are passing the unconverted JMS message (com.ibm.jms.JMSMessage) to the XML Payload converter...
org.springframework.integration.MessagingException: unsupported payload type [com.ibm.jms.JMSMessage]
at org.springframework.integration.xml.DefaultXmlPayloadConverter.convertToDocument(DefaultXmlPayloadConverter.java:76)
Perhaps you have set extract-payload to false ?
Although it's not in the configuration you show.
Turning on DEBUG logging will show the payload type of messages passing through the system.
The issue was because of valid and poisonous(which has a payload type [com.ibm.jms.JMSMessage]) messages we were getting onto queue. Valid messages processed well, but poisounous messages not able to digest by application and send to the BackoutQueue.
In our case, BOQ threshold is 3 that means 3 times my application will try to consume a perticular message and if the message backout 3 times then it will be moved to BOQ queue and (msgs read - msgs put)/3 on LOAIQ == the msgs put on to BOQ queue at that sampling interval. From msgs put on BOQ queue, we can see how many messages are backout from LOAIQ queue. That is why the message read count is more than that of msg received.

What is the preferred way to do a "Destination Bridge" featuring Message selectors in Websphere MQ?

In TIBCO EMS, which I am familiar with, there is a feature called "destination bridges".
Queues and Topic can be bridged (linked) so that the 2nd destination can become client of the the first. (Queue to queue, Topic to queue, Queue to topic, topic to topic)
For instance, a topic can be bridged to a queue, which in essence will become a durable subscriber of the messages submitted to the topic. Clients can subscribe to the topic OR read from the queue. This example is a way to load balance the reading of a pub/sub for multiple clients (readers of the queue).
This "bridge" feature can also involve message selectors and destination name wilcards.
So, a QUEUE X can be the client of TOPIC.* with condition CUST_ID(a JMS attribute)>30.
In that case, all message submitted to TOPIC.A OR TOPIC.B fitting the criteria would end up in QUEUE X. All this does not involve anything but simple EMS configuration.
I don't know enough about Websphere MQ, and I need a similar behavior. Will I have to develop a processing program outside of MQ, or can the feature within the product sufice ?
Note : I have already gone through MQ documentation and found about the "Alias queues" feature. Since the feature should really be called "Shortcut queue" and does not involve 2 destinations... I don't think it could help me...
Thanks!
Edit : For reference, the command (DEF SUB) enabling this in MQ is documented here
Edit 2 : The selected answer cover the "Topic -> Queue" pattern from TIBCO EMS "Destination bridge" featuire. Please note that the "Q->Q", T->T and Q->T" patterns are not covered here.
Easy! Define your queue to receive the subscription and then define a durable administrative subscription.
DEF QL(MY.SUSCRIBER.QUEUE)
DEF SUB('MY.SUBSCRIPTION') +
TOPICSTR('SOME/TOPIC/#') +
DEST('MY.SUSCRIBER.QUEUE') +
SELECTOR('JMSType = 'car' AND color = 'blue' AND weight > 2500') +
REPLACE
The Infocenter has a section on Selector Syntax and a page for the DEFINE SUB command.

Changing state of messages which are "in delivery"

In my application, I have a queue (HornetQ) set up on JBoss 7 AS.
I have used Spring batch to do some work once the messages is received (save values in database etc.) and then the consumer commits the JMS session.
Sometimes when there is an exception while processing the message, the excecution of consumer is aborted abruptly.
And the message remains in "in delivery" state. There are about 30 messages in this state on my production queue.
I have tried restarting the consumer but the state of these messages is not changed. The only way to remove these
messages from the queue is to restart the queue. But before doing that I want a way to read these messages so
that they can be corrected and sent to the queue again to be processed.
I have tried using QueueBrowser to read them but it does not work. I have searched a lot on Google but could not
find any way to read these messages.
I am using a Transacted session, where once the message is processed, I am calling:
session.commit();
This sends the acknowledgement.
I am implementing spring's
org.springframework.jms.listener.SessionAwareMessageListener
to recieve messages and then to process them.
While processing the messages, I am using spring batch to insert some data in database.
For a perticular case, it tries to insert data too big to be inserted in a column.
It throws an exception and transaction is aborted.
Now, I have fixed my producer and consumer not to have such data, so that this case should not happen again.
But my question is what about the 30 "in delivery" state messages that are in my production queue? I want to read them so that they can be corrected and sent to the queue again to be processed. Is there any way to read these messages? Once I know their content, I can restart the queue and submit them again (after correcting them).
Thanking you in anticipation,
Suvarna
It all depends on the Transaction mode you are using.
for instance if you use transactions:
// session here is a TX Session
MessageConsumer cons = session.createConsumer(someQueue);
session.start();
Message msg = consumer.receive...
session.rollback(); // this will make the messages to be redelivered
if you are using non TX:
// session here is auto-ack
MessageConsumer cons = session.createConsumer(someQueue);
session.start();
// this means the message is ACKed as we receive, doing autoACK
Message msg = consumer.receive...
//however the consumer here could have a buffer from the server...
// if you are not using the consumer any longer.. close it
consumer.close(); // this will release messages on the client buffer
Alternatively you could also set consumerWindowSize=0 on the connectionFactory.
This is on 2.2.5 but it never changed on following releases:
http://docs.jboss.org/hornetq/2.2.5.Final/user-manual/en/html/flow-control.html
I"m covering all the possibilities I could think of since you're not being specific on how you are consuming. If you provide me more detail then I will be able to tell you more:
You can indeed read your messages in the queue using jmx (with for example jconsole)
In Jboss As7 you can do it the following way :
MBeans>jboss.as>messaging>default>myJmsQueue>Operations
listMessagesAsJson
[edit]
Since 2.3.0 You have a dedicated method for this specific case :
listDeliveringMessages
See https://issues.jboss.org/browse/HORNETQ-763

Resources