ActiveMQ getClientId and removeinfo objectid don't match - java

i have an ActiveMQ java client that needs to detect other client connect/disconnect events.
by subscribing to connection advisory topic that is provided by AdvisorySupport.getConnectionAdvisoryTopic(), i've noticed that i get different client/connection/removeinfo ids.
for example, calling .getClientId() directly on the connection object returns an id like this:
ID:computername-60117-1388179017343-0:1
receiving the connection id via advisorySupport topic subscription, i see an id that is almost the same, like this:
ID:computername-60117-1388179017343-1:1
(note second to last number is one greater)
finally, looking at the id returned by a disconnection event, via removeInfo.getObjectId, i also get an id like this:
ID:computername-60117-1388179017343-1:1
so my question is: why are the ids in the messages received via advisorySupport topic subscriptions always one greater than the id returned by connection.getClientId()?

Related

Processing just one service bus topic message at a time

I am subscribed to a Azure servicebus topic made by an external department. The way I want the code to work is as follows:
Trigger an http endpoint that starts processorClient and listens to the topic.
Fetches one message
Does required actions to that message
Closes processorClient connection.
Repeat
I am using the ServiceBusProcessorClient class as shown in the following documentation Receive messages from a subscription
Is there a way to utilize this code in order to only fetch one message from the topic at a time before calling the processorClient.close();
I have tried using setting maxConcurrentCalls and setting prefetchCount(0).

Processing messages with PossDupFlag set with QuickFixJ

In QuickFix/J we can send a ResendRequest message to the Acceptor to request messages to be resent to the Initiator, within a given MsgSeq number range. For example:
Session session = Session.lookupSession(new SessionID("FIXT.1.1:SENDER->TARGET"));
session.send(new ResendRequest(new BeginSeqNo(1), new EndSeqNo(0)));
This message will request all existing Execution Reports for any open orders in the Acceptor.
The issue we have is that these messages come with PossDupFlag set to Y in the header. QuickFix/J by default ignores these messages and doesn't call the fromApp callback. I found that the callback is called if we set
ValidateSequenceNumbers=Y
but, as per the documentation, it has a drawback
If not enabled and a mismatch is detected, nothing is done.
I was wondering:
is there a different way for these messages to be processed by the callback?
if there is no other way what are the consequences of setting ValidateSequenceNumbers=Y? Is it just detect the sequence number mismatch ourselves?
Thanks
After some digging around I found a solution for this problem. Basically, we need to tell QuickFix/J that our target MsgSeqNum is 1. The logic will detect that the actual target's MsgSeqNum is higher than the one we have set and it will send a ResendRequest to the Acceptor:
Session session = Session.lookupSession(new SessionID("FIXT.1.1:SENDER->TARGET"));
session.setNextTargetMsgSeqNum(1);
In this case, the fromApp callback is called even though the PosDupFlag is set in the messages.

Can I subscribe to a durable topic endpoint using wildcards in Solace using Java?

The idea is to send messages to topic and consume them in stripes via pub/sub only (without queues) and using PERSISTENT delivery mode. For simplicity, lets say producer(s) publish messages to specific topics having the following hierarchy: bus/<componentId/<transactionId>.
Consumers want to receive topic "stripes", for simplicity lets say there are 10 consumers and they want to stripe traffic among themselves by transactionId:
bus/*/0*
bus/*/1*
...
bus/*/9*
When I try to subscribe to topic endpoint using wildcards, like this:
DurableTopicEndpoint topicEndpoint = JCSMPFactory.onlyInstance().createDurableTopicEndpoint("bus/*/1*");
ConsumerFlowProperties propsFlow = new ConsumerFlowProperties();
propsFlow.setEndpoint(topicEndpoint);
I get the following exception:
Exception in thread "main" java.lang.IllegalArgumentException: Topic Endpoint name "bus/*/1*" contains illegal character [*]
at com.solacesystems.common.util.DestinationUtil.isValidEndpointName(DestinationUtil.java:234)
at com.solacesystems.common.util.DestinationUtil.isValidTopicEndpointPhysicalName(DestinationUtil.java:209)
at com.solacesystems.common.util.DestinationUtil.isValidDTEPhysicalName(DestinationUtil.java:213)
at com.solacesystems.jcsmp.impl.SessionModeSupport.createFlow(SessionModeSupport.java:247)
at com.solacesystems.jcsmp.impl.SessionModeSupport.createFlow(SessionModeSupport.java:170)
at com.solacesystems.jcsmp.impl.JCSMPBasicSession.createFlow(JCSMPBasicSession.java:953)
In the light of this article's section "Adding Subscriptions to Topic Endpoints" - is it at all possible with Solace Java API?
There are two problems here.
You are trying to create an TopicEndpoint named bus/*/1*. Note that this is the name of the TopicEndpoint and not the topic that it is subscribing to. * is not a valid character for the name of a TopicEndpoint.
TopicEndpoints are only allowed to have one subscription. This means that you can only subscribe to bus/*/0*. If you want to subscribe to bus/*/0* all the way to bus/*/9* you will need to make use of a Queue instead of a TopicEndpoint.

COD received has correlationID and body as null

We are sending a message to Websphere MQ Queue. While sending the message we are setting the REPLY TO QUEUE NAME and JMSCOrrelationID. We also set the USER IDENTIFIER. The code snippet is as follows.
Message msg = session.createTextMessage((String) message);
Destination codeDestination = session.createQueue("queue://" + replyToQueueMgr + "/" + replyToQueueName);
msg.setJMSReplyTo(codeDestination);
msg.setIntProperty(JmsConstants.JMS_IBM_REPORT_COD, MQC.MQRO_COD);
msg.setJMSCorrelationID(msgCorrelId);
msg.setStringProperty(JmsConstants.JMS_IBM_MQMD_USERIDENTIFIER, "abc");
producer.send(msg);
Please note that we have ensure that all the fields which we set are not null. Also the user abc is a valid user because if not then the CODs should go to DEAD LETTER QUEUE but there are no messages in it. Still after the message is picked up we get a COD which has JMSCorrelationID as null. In COD Processor we are listening on the replyToQueuename.
String correlationID = (String)eventContext.getMessage().getInboundProperty("JMSCorrelationID");
On checking above correlation ID is null. ALso the message payload is of {null_payload} type of NullPayload class of mule. I know that body would be NULL because we set MQC.MQRO_COD. But I dont undertand how the correlationId got wiped out.
Please advise if there is any configuration at the Webview MQ end whih could cause such a behaviour? Or is there something missing in the way we are setting the header properties?
UPDATE
The queue that we are sending the message to with COD information is an alias to a TOPIC. There are 2 subscribers to this TOPIC and we observed that there were instances where we received multiple COD's when both the subscribers picked up the messages. Is there any way to ensure that the TOPIC sends a single COD after all the subscribers have picked up the message? Could this QM setup be the cause of the COD with null?
User Identifier
When a message is published, each subscriber gets a copy of the message with a unique message ID and with the identity context fields in the MQMD (UserID, AccountingToken, ApplIdentityData) all set to the subscriber's context. So it doesn't matter what you set in the MQMD UserID of the message you publish, all the copies will have the subscriber user ID in them. This user ID will, by definition, exist where he subscriber is so the CODs will be able to be put.
Correlation ID with Pub/Sub
You can ensure the correlation ID from the publisher is sent all the way through to the subscriber, by ensuring the subscription is made using MQSO_SET_CORREL_ID and setting the MQSO SubCorrelId to MQCI_NONE.
One COD for multiple messages
Since there are multiple independent messages, each with the COD Report Option set, you will get multiple report messages. There is no setting to combine these, however you could write an intermediate application to combine then if your main application wants only one.
Passing Correl ID back in a Report Message
By default the report option will send back the message ID in the Correl ID of the report message. If you want to have the Correl ID passed back, you should use MQRO_PASS_CORREL_ID.
Further Reading
Report Option
The issue is not with MQ configuration but with Mule endpoint configuration. The COD which were sent with nullpayload were actually sent by my own mule application jmsRepyToHandler. There is some default configuration in Mule which seems to be causing this behavior.
Analysis
Application sends a message to the Queue which is alias to a TOPIC with two subscribers
Once both the subscribers consume the message we get 2 COD as expected.
These COD are consumed by my MULE application and after processing the MULE application again sends COD to same queue with null correlation Id.
UPDATE: Mule Fix to avoid default ReplyTo
For the fix you need to override getReplyToHandler method of Mule JMSConnector as follows
if (disableReplyTo) {
return new DisableJmsReplyToHandler(this, getDefaultResponseTransformers(endpoint));
}else {
return super.getReplyToHandler(endpoint);
}
Set the property disableReplyTo as true so that above code provide DisableJmsReplyToHandler instead of the default one.

how to create multiple instances of activemq topic subscribers using virtual destinations?

I have a publisher that is pushing messages to a topic. I have multiple subscribers each doing a different task once they consume the message from the topic.
Now I want my system to scale to multiple instances of the same process running on different hosts/same host. e.g. I want to run multiple copies of my application A on different hosts so that if one instance of A is slow, then the other instances can pull in subsequent messages and make forward progress..
I found out that this is possible using virtual destinations. I followed the steps here -
http://activemq.apache.org/virtual-destinations.html
But how do i setup my multiple subscribers to the same topic with the same client id? when i try to do that, i get errors. when i try some other way, it doesn't work. can someone help?
Normally, I start a subscriber by doing the below steps -
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, ActiveMQConnection.DEFAULT_BROKER_URL;);
activeMQConnection = connectionFactory.createConnection();
activeMQConnection.setClientID("subscriber1");
activeMQConnection.setExceptionListener(exceptionListener);
activeMQSession = activeMQConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
activeMQTopic = activeMQSession.createTopic("myTopic");
activeConsumer = activeMQSession.createDurableSubscriber(activeMQTopic, "myTopic");
activeConsumer.setMessageListener(messageListener);
activeMQConnection.start();
when i try to create a 2nd subscriber and pass the topic name as "VirtualTopic.myTopic", nothing happens.
thanks
The virtual topics feature is very simple and quite powerful once you understand it.
When using virtual topics - there is no need for durable consumers. That is because for each client you will get an instance of regular queue created. If you have 5 clients (application A, B, C, D, E) you will get 5 queues created and populated with the copy of the messages every time message is sent to the virtual topic.
Actually it is a limitation of durable consumer - that only ONE connection is allowed per clientId. Being a regular queue, you can create as many consumers as you like and queue will guarantee that 1 message will be received only by 1 consumer. So if you have application A that takes 1 minute to process a message, you can create 5 instances of it listening to the same queue. When you will post 5 messages within 1 second, each of your application will receive its own message to process.
There are not well documented requirements which are not intuitive. To make virtual topic work you need
Use VirtualTopic. in your topic name, for example VirtualTopic.Orders (this prefix can be configured)
Use Consumer. in the name of the queue you. Like Consumer.ApplicationA.VirtualTopic.Orders where ApplicationA is actually your client id
Use regular subscribers not durable ones for the queue above.
Example:
string activeMqConsumerTopic = "Consumer.AmqTestConsumer.VirtualTopic.Orders";
IQueue queue = SessionUtil.GetQueue(session, activeMqConsumerTopic);
IMessageConsumer consumer = session.CreateConsumer(queue);
Queue is created for automatically whenever the first instance of consumer is subscribed to it. Since that moment all messages that are sent to topic are duplicated/copied into all associated queues.
Hope this helps.
Virtual Topics is the answer for you. However you have to define a naming standard for all virtual topic queues. Here is the answer for this:
Virtual Topics helps with following prospective:
1. Load Balancing of messages
2. Fast Failover of Subscriber
3. Re-using same connection Factory for different Producers and Consumers. (Durable Subscribers needs a Unique JMS Client Id and same cannot be reused for any other Producer or consumer)
here is the way to do it, below example creates prefix VTCON.*. So every queue with this prefix and Topic Name at the end will consumer the message.
<virtualDestinations>
<virtualTopic name="TEST.TP01" prefix="VTCON.*." selectorAware="false"/>
</virtualDestinations>
http://workingwithqueues.blogspot.com/2012/05/activemq-virtual-topics-or-virtual.html

Categories