QueueReceiver receive() does not receive messages - java

I've created a synchronous QueueReceiver attached to a WebLogic queue.
doStuff() {
ctx = new InitialContext();
qconFactory = (QueueConnectionFactory) ctx.lookup(CONNECTION_FACTORY);
queue = (Queue) ctx.lookup(outputFromOrcSyncQueue);
queueConnection = qconFactory.createQueueConnection();
queueSession = queueConnection.createQueueSession(true, -1);
queueReceiver = queueSession.createReceiver(queue);
Message message = queueReceiver.receive();
...
}
true in queueSession creation it's is because the connection factory is transacted.
If i create a no transacted queueSession (by putting false) the result is that the queueReceiver seems to ignore the receive() method going through the doStuff method (same behaviour using receive(timeout), it does not wait before going through).
I've also had to enable Prefetch Mode for Synchronous Consumer on my connection factory (Client tab in WebLogic connection factory's configuration).
My problem is the receiver does not read any message sent to the queue.
I can see my messages on WebLogic console, I can even see my queueReceiver listening on the queue, but the queueReceiver seems to ignore them.
Alternatives ways I've tried:
Changing ACK type in queueSession creation (both sides, producer and consumer)
Commit the session on producer after send() and before close()
Thank you.

You forgot to call the start method on the QueueConnection:
queueConnection = qconFactory.createQueueConnection();
queueConnection.start();
queueSession = queueConnection.createQueueSession(true, -1);
As The JMS API Programming Model in the Java EE Tutorial helpfully says:
Before your application can consume messages, you must call the connection’s start method.
The JMS Message Consumers section makes it more clear:
Remember always to call the start method; forgetting to start the connection is one of the most common JMS programming errors.

Related

Messages with persistence get stuck in ActiveMQ embedded in Tomcat

I am trying to integrate ActiveMQ within Tomcat. To that end, I used this tutorial (a little outdated, I know, but the best I found). I created a servlet that instantiates and starts a broker:
try {
broker = new BrokerService();
broker.addConnector("tcp://localhost:61616");
broker.start()
} catch (final Exception e) {
e.printStackTrace();
}
I then created a simple Hello World example with a single producer sending a persisted message to a queue and a consumer retrieving the message, which failed. Both, producer and consumer, were able to connect to ActiveMQ and the queue but the consumer did not receive any message. However, after restarting Tomcat (and consequently the broker), the consumer received the message previously sent. Any newly created messages were again stuck.
I tried some non-persisted messages, which all arrived as expected. When sending a combination of persisted and non-persisted messages, the non-persisted ones arrived immediately and the persisted ones required a restart.
This is my (very basic) code for the producer and consumer:
final ConnectionFactory conFactory = (ConnectionFactory) jndi.lookup("connectionFactory");
final Connection connection = conFactory.createConnection();
connection.start();
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
final Destination destination = (Destination) jndi.lookup("MyQueue");
final MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
final TextMessage message = session.createTextMessage("Hello World!");
producer.send(message);
connection.close();
final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
connectionFactory.setTrustAllPackages(true);
final Connection connection = connectionFactory.createConnection();
connection.start();
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
final Destination destination = session.createQueue("APP.JMS.QUEUE");
final MessageConsumer consumer = session.createConsumer(destination);
final Message message = consumer.receive(1000);
System.out.println("Received: " + message);
consumer.close();
session.close();
connection.close();
I tried transacted, manual-acknowledge, and auto-acknowledge mode for the consumer. I also tried directly creating ConnectionFactory and Destination (as in the consumer code) as well as JNDI lookup (producer code). All yielded the same result.
I tried versions 5.15.12, 5.15.11, 5.14.5, 5.11.0 and 5.10.0.
Any pointers what I did wrong or where I can find a more recent tutorial? I am aware of the official docs regarding ActiveMQ and Tomcat but they seem to be missing the essential parts.

Process the jms messages sequentially/concurrently?

My JMS consumer produces any number(Say n) of messages on JMS queue during the day. First I am evaluating the synchronous processing of message
Say at 23.0 clock, now I want to consume all messages. Here is main method
Here's how to do it sequentially(not concurrently) :-
Do I need to call consumer.receive() method n times (till returns consumer.receive() return null )on single consumer?
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost");
// Create a Connection
Connection connection = connectionFactory.createConnection();
connection.start();
// Create a Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the destination (Topic or Queue)
Destination destination = session.createQueue("TEST.FOO");
// Create a MessageConsumer from the Session to the Topic or Queue
MessageConsumer consumer = session.createConsumer(destination);
// Wait for a message
Message message = consumer.receive();
How to do it concurrently :- I want to process the 20 messages concurrently
Do I need to create 20 thread where each thread creates its own consumer and the receive the message?
To process 20 messages sequentially, and you know you will receive at least 20 messages, put the MessageConsumer.receive() call into a loop 20 times. Note that MessageConsumer.receive() without a timeout argument will not return null if there are no messages on the queue. It will block until it receives a message, or until close() is called. If you use MessageConsumer.receive(longTimeoutValue), it will wait for longTimeoutValue to receive a message, and will return null if no message is received by then.
For concurrent message processing, the ActiveMQ docs provide a sample of how to use multiple consumers here: http://activemq.apache.org/hello-world.html, which you can modify for your purposes. The sample creates a new connection per thread, but according to http://activemq.apache.org/multiple-consumers-on-a-queue.html, you are only required to create a session and consumer per thread.

Unable to get ActiveMQ to dequeue

There might be a stupid simple answer to this, but I'm trying to use ActiveMQ to pass messages between producers and consumers. I will have many producers and many consumers, but I want each message to be delivered only once among the consumers. This would seem to mean that I cannot use Topics, since they would deliver messages to all consumers who are listening, and I want only one Consumer to receive each message.
My problem is that I am able to receive messages, but the messages are not dequeued. So if I restart my consumer process, all of the messages are reprocessed. This answer seems pertinent but does not seem to apply since I can't create durable queue consumers, only durable topic consumers (unless I'm missing something in the API docs).
My code is as follows.
TopicConnectionFactory factory = new ActiveMQConnectionFactory(props.getProperty("mq.url"));
Connection conn = factory.createConnection();
Session session = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE);
Queue queue = session.createQueue(props.getProperty("mq.source_queue"));
conn.start();
MessageConsumer consumer = session.createConsumer(queue);
Then later on
Message msg = consumer.receive();
msg.acknowledge();
if (!(msg instanceof TextMessage)) continue;
String msgStr = ((TextMessage)msg).getText();
This is my current code. I have tried with Session.AUTO_ACKNOWLEDGE and without msg.acknowledge(). Any working permutation of this code seems to retrieve the messages, but when I restart my consumer, all of the messages get received again, even if they have been received prior to the restart.
You created the session as a transacted Session and therefore need to call, session.commit if you want to inform the broker that all messages are now consumed and don't need to be redelivered. If you don't set the first argument to createSession to true then the Ack mode is respected otherwise its ignored, one of the oddities of the JMS API I'm afraid. If you do this:
ConnectionFactory factory = new ActiveMQConnectionFactory(props.getProperty("mq.url"));
Connection conn = factory.createConnection();
Session session = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
Queue queue = session.createQueue(props.getProperty("mq.source_queue"));
conn.start();
MessageConsumer consumer = session.createConsumer(queue);
Then this would work:
Message msg = consumer.receive();
msg.acknowledge();
Otherwise you need to do:
Message msg = consumer.receive();
session.commit();
But keep in mind that for a single message transactions don't really make sense to client ack with no transaction is a better option.

How to get all enqueued messages in ActiveMQ?

I want to build a simple consumer program (in java) to get all messages stocked in an ActiveMQ subject.
I have a producer which send TextMessage in the queue.
But I don't know how to start to write my consumer for retrieving old messages and wait for new one.
If you have an example, thanks!
This is my Producer: http://pastebin.com/uRy9D8mY
This is my Consumer: http://pastebin.com/bZh4r66e
When I run my producer before my consumer, then run the consumer, I got nothing.
When I run my consumer then my producer, I add 72 messages in the queue but my consumer got only 24 message...
I suggest reading this tutorial (as does Apache ActiveMQ) SUN Jms tutorial
There are many ways to write JMS/ActiveMQ programs, using various frameworks such as Spring, or by using plain java.
Essentially, write a listener class like this:
public class MyListener implements MessageListener{
public void onMessage(Message message){
// Read and handle message here.
}
}
Since you already are producing message, I assume you have connection up and running.
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
consumer = session.createConsumer("MyQueue");
listener = new MyListener ();
consumer.setMessageListener(listener);
connection.start();
// At this point, messages should arrive from the queue to your listener.
Then there are some error handling code not included in this example, but you should be able to figure it out with the help of the tutorial and JMS documentation.
Using the code given below you can read all the messages en-queued in the queue.
In this code the while loop is an unending loop it will iterate all
the messages in the queue.
Once there is no messages in the queue it will wait for 5 seconds then automatically stops the connection and breaks
the loop.
If you required an unending consumer which will read all the messages whenever newly added to the queue, then remove the else part, so the program will not terminate.
ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection con = factory.createConnection();
Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("tmp_queue2");
MessageConsumer consumer = session.createConsumer(queue);
con.start();
while (true) {
Message msg = consumer.receive(5000);
if (msg instanceof TextMessage) {
TextMessage tm = (TextMessage) msg;
System.out.println(tm.getText());
}
else{
System.out.println("Queue Empty");
con.stop();
break;
}
}
Hope this consumer program will helps people who were new to ActiveMQ.

MDB onMessage does not begin until ejbTimeout ends. Shouldn't it start asynchronously?

We have a javax.ejb.TimedObject which queues messages to an MDB like so...
ctx = new InitialContext();
QueueConnectionFactory qCF = (QueueConnectionFactory) ctx
.lookup("java:comp/env/jms/queueconnfactory");
Queue q = (Queue) ctx.lookup("java:comp/env/jms/queue");
conn = qCF.createQueueConnection();
session = conn.createQueueSession(true,
Session.AUTO_ACKNOWLEDGE);
QueueSender sender = session.createSender(q);
TextMessage txtMsg = session.createTextMessage();
txtMsg.setLongProperty(JobMonitorUtil.JOB_REFERENCE_ID, filingId);
txtMsg.setLongProperty(JobMonitorUtil.JOB_ID, jobId);
txtMsg.setLongProperty(JobMonitorUtil.JOB_RUN_SID, jobRunSId);
sender.send(txtMsg);
session.close();
conn.close();
When I debug this (on Weblogic 10.3.1.0) I step over the sender.sent(txtMsg) line and I expect my onMessage breakpoint to be hit almost instantaneously. It doesn't hit my breakpoint until I let the ejbTimeout run (actually when I step out of TimerImpl.timerExpired). The message queue is on the same server which generates the messages.
To me it seems odd.
Aren't MDB messages sent asyncronously?
Could this be a configuration problem or is this how it's supposed to work?
You created a transactional session. JMS messages are not sent out until transaction is committed (otherwise rollback wouldn't be possible -- message has reached the remote system already).
The transaction is committed when you call session.close().
Solution would be (for example) to create a non-transactional session:
session = conn.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);

Categories

Resources