We are facing a problem, where every 15th message does not get read from the message queue until an MDB instance does not finish working on the first message.
We have a timeToLive of 30 secs for the messages. If the first message consumption takes much more time then that, then the stuck messages stay in the queue for more then 30 secs, and thus timeout when the slow message consumption stops.
MDB pool size is 20, but have tried 30, 10, ... makes no difference.
the scenario looks like this:
#1 SLOW message goes in queue, MDB onMessage() called, message processing.
#2-14 messages go in queue, MDB onMessage() called, messages processed.
#15 message goes in queue, message not touched.
#16-29 messages go in queue, MDB onMessage() called, message processed.
#30 message goes in queue, message not touched.
... every 15th gets stuck
#1 finishes, then immediately every 15th message (which got stuck) gets thrown away due to message timeout.
It's always every 15th message...
We are on JBOSS EAP 6.1 and using JAVA 7
Can anyone give us some tips on this issue, what could be the cause, where to look? Something has to be configured to a number of 15 which is causing this, but we have no clue on to what it could be.
Thanks in advance!
I have solved the problem.
It is because of hornetq window based flow control.
This post contains the solution:
JMS queue with multiple consumers
Related
I currently switched to version 0.24.0-beta of the google-cloud-pubsub library and can't find a way to modify acknowledge deadline of the message. In the previous version there was a modifyAckDeadline(), which allowed me to do it. Is it possible in the new version?
To get an idea why I'm trying to it: What I want to achieve is a kind of retry mechanism where messages that failed to process are redelivered in 10 minutes, and acked only after X such unsuccessful retries.
For purposes of keeping the lease on a message because it will take longer to process, the new version of the subscriber library calls modifyAckDeadline in the background for you. As long the message is outstanding, i.e., you haven't called ack() or nack() on the AckReplyConsumer that your MessageReceiver receives with the message, the library itself will call modifyAckDeadline on the message.
Your goal is a little different: you want to use modifyAckDeadline to best-effort prevent message redelivery for a time. If the time you want to wait is always going to be 10 minutes, then the best thing to do is to call setMaxAckExtensionPeriod() with a duration of 10 minutes on the Subscriber.Builder when creating your subscriber. Then, when you fail to process a message, just don't ack or nack the message. The client library will continue to modifyAckDeadline for ten minutes, after which the message can be redelivered.
Using Spring-boot and Spring-starter-amqp for my messaging app. My Problem scenario is this :
First Problem : I want to requeue my message only for 5 times and then message should be comeout from queue if business exception occurs(here I am focusing only on business exception).
Second Problem : If first use case is possible, can we somehow increase time to requeue based on the attempts. Suppose in the first attempt business exception occurs it should requeue immediately but in the second attempt it should requeue after 2 mins then 4 mins then 6 mins then 8 mins then 10 mins like time will increase based on the attempt.
Thanks
For the simple case (fixed delay between attempts), you can configure the queue to send rejected messages a dead letter exchange, and throw AmqpRejectAndDontRequeueException.
Bind a queue to the dead letter exchange, and set a time to live (ttl) on that queue and also configure it with a dead letter exchange to which the original queue is bound. The message will be requeued after the TTL expires.
You would need to examine the x-death header to determine how many times around the loop the message has traversed. After your retries are exhausted, throw an ImmediateAcknowledgeAmqpException to discard the message.
For a variable delay, you have to republish the message yourself, to a delayed-message exchange (there's a broker plugin for that), with the delay increasing for each retry.
Also see this answer.
I have a system that reads messages from a IBM MQ. From this queue we sometimes get corrupt data. If a message has failed the next time it is read the listener will wait 5 minutes before proceeding. When a message has failed 3 times it is put on a Backoff-queue. The JMSContainerFacotry is set up to run max 10 in parallell. This means if we get a big batch of corrupt messages these messages take 10+ minutes each to reach the Backoff-queue (which is ok), but they end up consuming all the threads so other messages must wait for all the corrupt to reach the Backoff-queue before being processed. I want to remove the wait() from the listener so that this doesnt block threads, but that failed messages still wait 5 minutes before popping back up.
I know that with ActiveMQ you can tell the queue to wait 5 minutes before popping the same message again, with IBM MQ I dont have that possibility. Is it possible to put failed messages to the back off the queue? Now failed messages seems to pop in front of new ones. Or set the jmspriority on failed messages lower. So that if there is messages that have yet to fail will get popped from the queue before those that have failed?
My listener is about so:
#JMSListener()
public void listen(Object message) {
TextMessage textMessage = (TextMessage) message;
if (textMessage.getIntProperty("JMSXDeliveryCount") > 1) {
//pause for 5 minutes
}
//buisness logic
}
The in-queue is a IBM MQ. AS is Jboss 6.
Not sure why you're pausing for 5 minutes if you get a poison message. If you know it's bad why aren't you either throwing it away or passing it to a backout queue for further investigation? See JMS poison message handling:
http://www.ibm.com/support/knowledgecenter/SSFKSJ_9.0.0/com.ibm.mq.dev.doc/q032280_.htm
More concerning, why are you getting so many 'bad' messages?
I know that with ActiveMQ you can tell the queue to wait 5 minutes
before popping the same message again, with IBM MQ I dont have that
possibility.
The option of retry interval between attempts need to be set on the MDB listener side, since it is acting as client. But not on WMQ side.
Is it possible to put failed messages to the back off the queue?
You wanted to place the message back on the queue or place the poisonous messages at the end of the same queue ? we can't move poison messages to the end of the same queue
There are only three options to handle poisonous messages:
Place the message back on the queue
re-route the message either to BOQ or DLQ
Purge or discard it permanently.
I am using ActiveMQ version 5.7.x,
I am having one ActiveMQ queue to which the listener listens.
Queue has a ConnectionFactory whose redeliveryPolicy is set to 3, intialRedeliveryDelay set to 5000.
Queue have some good messages and bad messages. While listening to such queue, when bad messages come, they are tried 3 times with the wait time of 5000 millis, but then the good messages are blocked for that much time span.
What I want is, during the wait time of 5000 millis for each retry, the processing of good messages should continue and should not wait for bad message processing.
For this I tried 1 attribute of connectionFactory, i.e. nonBlockingRedelivery set to true.
But nonBlockingRedelivery is not working.
Is there any other way to do this?
You can always have a retransmission queue for failing messages.
That is, receive messages from a main queue (no redelivery) and if you get an exception, put the message on a redelivery queue.
Let your application listen on both queues and do the same logic to both messages. It should simply be two message listeners invoking the same method. One with redelivery and one without, but with slightly different error handling.
Please look at the description of that attribute in ActiveMQConnectionFactory,
It says what I exactly what I wanted..
"When true a MessageConsumer will not stop Message delivery before re-delivering Messages from a rolled back transaction. This implies that message order will not be preserved and also will result in the TransactedIndividualAck option to be enabled"
But same is not working..!!!
Can you please look into it please?
Say you have two Spring DefaultMessageListenerContainer listening on the same Queue (ActiveMQ for example), started in different VMs.
Send 1 000 000 messages in. After 500 000 of messages you want the rest of them to be handled by only one DefaultMessageListenerContainer, BUT without calling destroy or shutdown on the other (since you might needed it in the future - and must keep it manageable with JMX). The numbers are just for example here and should be ignored, could be replaced with - "after some time, after some messages, etc etc"
This sounds easy : call stop on the other DefaultMessageListenerContainer. Wrong, since messages are dispatched in a Round Robin fashion and they get registered with the Consumer.
Add transaction support and throw an error in the second DefaultMessageListenerContainer every time a messages comes in, it will be rolled-back and taken (round-robin) by the first one. Wrong again, the messages somehow registers with the consumer, not allowing the first DefaultMessageListenerContainer to take the message.
Even if you you shutdown/destroy the first DMLC - the message is NOT consumed by the other DMLC. They ARE Consumed only if I kill the JVM that the now shutdown/destroyed DMLC was running in.
My Solution so far : Because of the Session.AUTO_ACKNOWLEDGE messages are taken out from the Queue before they enter the onMessage method in the MessageListener of the DefaultMessageListenerContainer. In the MessageListener implement SessionAwareMessageListener and re-send a fresh copy of the message with the same payload.
But this looks really dirty - I wish I could do it more in a "JMS"-ish way.
I don't fully grasp this part: "[the messages] get registered with the Consumer". Do you mean that ActiveMQ decides which listener to send it to? What exactly happens when you call "stop" on the DMLC?
I don't know if this is going to overcome your difficulties, but here's an idea: message selectors in DMLCs are live: you can change them any time and they are effective immediately. Perhaps try changing the message selector to "FALSE"; all cached messages should finish processing and new ones should stop coming.