Read messages from DLQ in Jboss 7 - jboss7.x

I have below two jms queues configured in JBOSS 7.1.
<jms-queue name="APP.QUEUE1">
<entry name="queue/APP.QUEUE1"/>
<entry name="java:jboss/exported/jms/queue/APP.QUEUE1"/>
</jms-queue>
<jms-queue name="APP.QUEUE2">
<entry name="queue/APP.QUEUE2"/>
<entry name="java:jboss/exported/jms/queue/APP.QUEUE2"/>
</jms-queue>
while consuming the message, if some thing goes wrong then the message will go to Dead letter Queue that is configured as follows.
<address-setting match="jms.queue.APP#">
<dead-letter-address>jms.queue.DLQ</dead-letter-address>
<expiry-address>jms.queue.ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<max-delivery-attempts>5</max-delivery-attempts>
<max-size-bytes>10485760</max-size-bytes>
<address-full-policy>BLOCK</address-full-policy>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
</address-setting>
so I have successfully delivered the message to DLQ.
Now I have written consumer for Dead letter queue, so that I can transfer back the message after fixing the issue.
the piece of code to consume the message is as follows.
QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueBrowser browser = session.createBrowser(queue);
Queue queue1=browser.getQueue();
Enumeration messageEnum = browser.getEnumeration();
while (messageEnum.hasMoreElements()) {
TextMessage message = (TextMessage) messageEnum.nextElement();
}
from the text message,is there any chance of getting source queue (APP.QUEUE1 or APP.QUEUE2), so that I have transfer back the same text message with out worrying much on message properties.
please let me know my approach is correct or not,appricite for better solution.

Found the answer for this.
we have property as follows.
message.getStringProperty("_HQ_ORIG_ADDRESS");
This property give originating address.

Related

Spring Integration: How to use an "error gateway" with Splitter Aggregator when Exception thrown

I've seen more than a few posts about this topic, but can't seem to find a solution to my specific problem, which I think is a pretty typical one, namely: how to keep processing messages when an error occurs (Exception thrown) using a Splitter / Aggregator.
The best explanation that I have come upon is here. But there's no explanation of exactly what/how the filters/transformers work. And in the end, the author posts "That worked!" but without posting an updated SI.config.xml.
From what I understand, the idea is to use an "error gateway", which is downstream from the original calling gateway and after the Splitter. This Gateway's job would be if there is an Exception thrown, to deal with it, but to make sure (via a transformer or a filter) that all Messages make it to the Aggregator.
My very simplified SI.config.xml if more or less like this:
<int:gateway id="myGateway" ... /> // incoming gateway
<int:chain ... input-channel="in" output-channel="out">
<int:splitter ... />
<int:service-activator />
<int:aggregator />
</int:chain>
So my question is, where exactly to stick this other gateway? And how to configure filters/transformers that (from what I gather) would grab the Message which launched an Exception and put it back on the correct channel (after logging it or whatever ...) so all Messages make it to the Aggregator.
I have looked at the SI samples, on SO, and the 2 SI books (SI in Acton and Pro SI) and can't find an example of this.
The solution looks like:
<int:chain ... input-channel="in" output-channel="out">
<int:splitter ... />
<int:gateway request-channel="processChannel" errorChannel="processError"/>
<int:aggregator />
</int:chain>
<int:chain input-channel="processChannel">
<int:service-activator />
</int:chain>
The error handler on the processError channel should consult incoming ErrorMessage and returns some compensation which will be sent to the aggregator.
The ErrorMessage typically contains MessagingException with a failedMessage where error has caused. That failedMessage contains all useful headers to go ahead with a compensation. Some of them are replyChannel and errorChannel, but for your aggregator case you need all those correlationId, sequenceNumber, sequenceSize etc. In other words when you build compensation message to be sent forward to the downstream for the aggregator, you should copy all the headers from that failedMessage.
For more info: http://docs.spring.io/spring-integration/docs/4.3.5.RELEASE/reference/html/configuration.html#namespace-errorhandler

Spring integration Error handling - How do I access original faulty message's history?

We have a spring-integration application where we would like to deal with the messages on the error channel.At a minimum we would like to extract the history and log it so we can visualise where exactly it failed etc
Here is a brief markup of just this bit
<int:poller id="defaultPoller" default="true" fixed-delay="5000" />
<int:channel id="MyCustomErrorChannel">
<int:queue capacity="10"/>
</int:channel>
<int:header-enricher id="errorMsg.HeaderEnricher"
input-channel="errorChannel"
output-channel="MyCustomErrorChannel">
<int:header name="history" expression="payload.failedMessage.headers" />
</int:header-enricher>
<int:service-activator input-channel="MyCustomErrorChannel" ref="errorLogger" method="logError"/>
<bean id="errorLogger" class="com.dataprep.util.ErrorLogger" />
The idea is to define our custom error channel MyCustomErrorChannel. Any error that ends up in the default errorChannel gets its header's enriched before being put out on MyCustomErrorChannel
Lastly we have a logger that reads the messages from MyCustomErrorChannel and logs the payload which is the underlying exception and also the history.
I notice that the history in my logger is always 3 steps
errorChannel,errorMsg.HeaderEnricher,pbSwiftRouterErrorChannel i.e nothing prior to this message landing on the errorChannel is obtainable in the history.
How do I get hold of the original message's history (i.e the history of the faulty message which somehow landed on the default error channel as a new Error Message)
Could you please take a look at my header enricher and let me know how to access the headers on the failed message and stuff it to the error message?
Is it doable at all ?
To replace existing headers you should use overwrite="true", because the history is built for the ErrorChannel, too.
You should override exactly with history header, not the whole headers. Therefore your expression must be like this:
<int:header name="history"
expression="payload.failedMessage.headers.history"
overwrite="true"/>

In RabbitMQ how to consume multiple message or read all messages in a queue or all messages in exchange using specific key?

I want to consume multiple messages from specific queue or a specific exchange with a given key.
so the scenario is as follow:
Publisher publish message 1 over queue 1
Publisher publish message 2 over queue 1
Publisher publish message 3 over queue 1
Publisher publish message 4 over queue 2
Publisher publish message 5 over queue 2
..
Consumer consume messages from queue 1
get [message 1, message 2, message 3] all at once and handle them in one call back
listen_to(queue_name , num_of_msg_to_fetch or all, function(messages){
//do some stuff with the returned list
});
the messages are not coming at the same time, it is like events and i want to collect them in a queue, package them and send them to a third party.
I also read this post:
http://rabbitmq.1065348.n5.nabble.com/Consuming-multiple-messages-at-a-time-td27195.html
Thanks
Don't consume directly from the queue as queues follow round robin algorithm(an AMQP mandate)
Use shovel to transfer the queue contents to a fanout exchange and consume messages right from this exchange. You get all messages across all connected consumers. :)
If you want to consume multiple messages from specific queue, you can try as below.
channel.queueDeclare(QUEUE_NAME, false, false,false, null);
Consumer consumer = new DefaultConsumer(channel){
#Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
logger.info("Recieved Message --> " + message);
}
};
You might need to conceptually separate domain-message from RMQ-message. As a producer you'd then bundle multiple domain messages into a single RMQ-message and .produce() it to RMQ. Remember this kind of design introduces timeouts and latencies due to the existence of a window (you might take some impression from Kafka that does bundling to optimize I/O at the cost of latency).
As a consumer then, you'd have a consumer, with typical .handleDelivery implementation that would transform the received body for the processing: byte[] -> Set[DomainMessage] -> your listener.

How to check number of pending messages or all messages are processed or not in ActiveMQ using mule flow

I have a requirement to stop the ActiveMQ connector if all messages have been processed in the queue. This needs to be done in Mule flow.
As shown below, I have two connectors one for reading and other for writing on vci.staging.queue. I want to check if all messages are processed in the queue then disable the reader connector.
Below piece of script to use client.request from muleContext using queue name and reader or writer connector is always returning ‘null’ for me.
Is there any way to get number of pending messages in a queue or to check if all messages are processed or not so that connector can be disabled?
<jms:activemq-connector name="jmsConnectorStagingQReaderNormal"
brokerURL="${mule.activemq.broker.read.normal.url}"
specification="1.1"
maxRedelivery="-1"
persistentDelivery="true"
numberOfConcurrentTransactedReceivers="${mule.activemq.concurrent.receivers}"
connectionFactory-ref="connectionFactory"
disableTemporaryReplyToDestinations="false">
</jms:activemq-connector>
<jms:activemq-connector name="jmsConnectorStagingQWriter"
brokerURL="${mule.activemq.broker.write.url}"
specification="1.1"
maxRedelivery="-1"
persistentDelivery="true"
numberOfConcurrentTransactedReceivers="${mule.activemq.concurrent.receivers}"
connectionFactory-ref="connectionFactory"
disableTemporaryReplyToDestinations="false">
</jms:activemq-connector>
<script:component>
<script:script engine="groovy">
if(muleContext.getRegistry().lookupConnector('jmsConnectorStagingQReaderNormal').isStarted()) {
if(muleContext.client.request("jms://vci.staging.queue?connector= jmsConnectorStagingQReaderNormal ", 5000) == null) {
muleContext.getRegistry().lookupConnector('jmsConnectorStagingQReaderNormal').stop()
}
}
return payload
</script:script>
</script:component>
Use a QueueBrowser to peek into a JMS queue without consuming its messages.
For this:
Create a custom component,
Have Spring inject your jms:activemq-connector in the component,
Call getSession(false, false) on it to get an active JMS Session,
Call createBrowser(Queue queue) on the Session (you can get a hold of the Queue with Session.createQueue(..).

sharedDeadLetterStrategy is not discarding the DLQ messages

Am using AMQ 5.5. I would like to disable the option of sending dead letters to ActiveMQ.DLQ destination and completely discard (automatically) the messages that would be sent there otherwise. To do this I had configured the broker as below:
<amq:destinationPolicy>
<amq:policyMap>
<amq:policyEntries>
<amq:policyEntry topic=">" producerFlowControl="false" >
<amq:deadLetterStrategy>
<amq:sharedDeadLetterStrategy processExpired="false" />
</amq:deadLetterStrategy>
</amq:policyEntry>
<amq:policyEntry queue=">" producerFlowControl="false">
<amq:deadLetterStrategy>
<amq:sharedDeadLetterStrategy processExpired="false" />
</amq:deadLetterStrategy>
</amq:policyEntry>
</amq:policyEntries>
</amq:policyMap>
</amq:destinationPolicy>
However, I still see that the messages are getting stored in DLQ. Can you please let me know what could be causing this?
Do I need to fix anything in the config?
Thanks
Hari
The problem faced here was that, the above given configuration would discard only non-persistent expired messages. To discard all expired messages, persistent and non-persistent, use discardingDLQBrokerPlugin.
<amq:plugins>
<amq:discardingDLQBrokerPlugin dropAll="true"/>
</amq:plugins>