JMSListener escapes '.' for durable subscriptions - spring-boot

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).

Related

How to Get message count in a durable subscriber in 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

ActiveMQ messageId not working to stop duplication

I am using ActiveMQ for messaging and there is one requirement that if message is duplicate then it should handled by AMQ automatically.
For that I generate unique message key and set to messageproccessor.
following is code :
jmsTemplate.convertAndSend(dataQueue, event, messagePostProccessor -> {
LocalDateTime dt = LocalDateTime.now();
long ms = dt.get(ChronoField.MILLI_OF_DAY) / 1000;
String messageUniqueId = event.getResource() + event.getEntityId() + ms;
System.out.println("messageUniqueId : " + messageUniqueId);
messagePostProccessor.setJMSMessageID(messageUniqueId);
messagePostProccessor.setJMSCorrelationID(messageUniqueId);
return messagePostProccessor;
});
As it can be seen code generates unique id and then set it to messagepostproccessor.
Can somehelp me on this, is there any other configuration that I need do.
A consumer can receive duplicate messages mainly for two reasons: a producer sent the same message more times or a consumer receive the same message more times.
Apache ActiveMQ Artemis includes powerful automatic duplicate message detection, filtering out messages sent by a producer more times.
To prevent a consumer from receiving the same message more times, an idempotent consumer must be implemented, ie Apache Camel provides an Idempotent consumer component that would work with any JMS provider, see: http://camel.apache.org/idempotent-consumer.html

Redelivery of JMS message in microserices

I want to know the redelivery of JMS in a microservices.
For example, if I have a microservices system. And I have 2 instances of User service. And have a listener on a destination in user service. It means I have 2 listeners. The listener is like this:
#JmsListener(destination = "order:new", containerFactory = "orderFactory")
#Transactional
public void create(OrderDTO orderDTO) {
Order order = new Order(orderDTO);
orderRepository.save(order);
jmsTemplate.convertAndSend("order:need_to_pay", order);
}
So my question is, how many times a message will be delivered. And if there is some error in this function, and the message will be re-delivered. But I have 2 instances of the service. And on which this message will be delivered?
It's not part of the spec; it depends on the broker configuration how many times it will be delivered; many brokers can be configured to send the message to a dead-letter queue after some number of attempts.
There is no guarantee the redelivery will go to the same instance.

Configure JMS for multiple clients feeding off same queue

So I have request/response queues that I am putting messages on and reading messages off from.
The problem is that I have multiple local instances that are reading/feeding off the same queues, and what happens sometimes is that one instance can read some other instance's reply message.
So is there a way I can configure my JMS, using spring that actually makes the instances read the messages that are only requested by them and not read other instance's messages.
I have very little knowledge about JMS and related stuff. So if the above question needs more info then I can dig around and provide it.
Thanks
It's easy!
A JMS message have two properties you can use - JMSMessageID and JMSCorrelationID.
A JMSMessageId is supposed to be unique for each message, so you could do something like this:
Let the client send a request, then start to listen for responses where the correlation id = the sent message id. The server side is then responsible for copying the message id of the request to the correlation id of the response. Something like: responseMsg.setJMSCorrelationID(requestMsg.getJMSMessageID());
Example client side code:
Session session = getSession();
Message msg = createRequest();
MessageProducer mp = session.createProducer(session.createQueue("REQUEST.QUEUE"));
mp.send(msg,DeliveryMode.NON_PERSISTENT,0,TIMEOUT);
// If session is transactional - commit now.
String msgID = msg.getJMSMessageID();
MessageConsumer mc = session.createConsumer(session.createQueue("REPLY.QUEUE"),
"JMSCorrelationID='" + msgId + "'");
Message response = mc.receive(TIMEOUT);
A more performant solution would be to use dedicated reply queues per destination. Simply set message.setJMSReplyTo(session.createQueue("REPLY.QUEUE."+getInstanceId())); and make sure the server side sends response to requestMsg.getJMSReplyTo() and not to a hard coded value.

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.

Resources