I am trying to create an application which keeps on checking the number of queues up and running in activemq.
And Any way to check whether queue's are working or not i.e. if corrupted and not able to process messages.
Kindly suggest how to do it.
Thanks in Advance.
You can try following code.
public static void main(String[] args) throws Exception
{
// get the initial context
InitialContext ctx = new InitialContext();
// lookup the queue object
Queue queue = (Queue) ctx.lookup("queue/queue0");
// lookup the queue connection factory
QueueConnectionFactory connFactory = (QueueConnectionFactory) ctx.
lookup("queue/connectionFactory");
// create a queue connection
QueueConnection queueConn = connFactory.createQueueConnection();
// create a queue session
QueueSession queueSession = queueConn.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
// create a queue browser
QueueBrowser queueBrowser = queueSession.createBrowser(queue);
// start the connection
queueConn.start();
// browse the messages
Enumeration e = queueBrowser.getEnumeration();
int numMsgs = 0;
// count number of messages
while (e.hasMoreElements()) {
Message message = (Message) e.nextElement();
numMsgs++;
}
System.out.println(queue + " has " + numMsgs + " messages");
// close the queue connection
queueConn.close();
}
You can ask for stats using the statistics plugin on the broker and the plain JMS api. I.e. to count the number of messages on FOO.BAR, send an empty message to ActiveMQ.Statistics.Destination.TEST.FOO and specify the replyTo header. In the response message, which is of typ MapMessage, you can find the message counter.
Another way is to browse only the first message of the queue using a simple queue browser (similar to the way praveen_programmer suggests) and check the timestamp of that message. If it's older than some threshold, you might have a problem with that consumer. I.e. no messages has been processed in the last hour/minute/day.
Yet another way is to use JMX, or preferably the jolokia REST/HTTP management api.
Just query the destination using http and you get a queue depth back:
To query the queue "q" on localhost, use the following api (you need to supply the user/password for the web console):
http://localhost:8161/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=q
Take a look at Advisory messages. You need to enable them in your config , but you can get a lot of useful about your current activemq instances info through simple JMS messaging. http://activemq.apache.org/advisory-message.html I was using them to highlight slow producer and consumer scenarios.
Related
I have ejb-jar.xml which contain <message-selector> destinationInstance IN(a', 'b','c')</message-selector>.
How we can implement message selector in standalone java program.
JMSMessageListener has been registered on queue and whenever there is message on queue , onMessage method of listener will be called.
I Have Try this.? Does It work...
public void messageSelector() {
List<String> url=StCotants.getUrls();
for(String obj:url){
ConnectionFactory factory = new ActiveMQConnectionFactory(obj);
System.out.println(factory);
try{
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("queue");
MessageConsumer consumer = session.createConsumer(queue,"destinationInstance IN('a', 'b','c')");
XyzMDBClient xyzClientlistener=new XyzMDBClient();
consumer.setMessageListener(xyzClientlistener);
}
catch(Exception e){
e.printStackTrace();
}
}
Back in time I was looking for examples on how to use message selectors and I found this site very usefull: How to use Message Selectors to filter messages
Very concise article about what selectors are and how to use them.
Message Selectors allow you to filter the messages that a MessageConsumer will receive. The filter is a relatively complex language that mimics the syntax of an SQL WHERE clause. The selector can use all message headers and properties for filtering, but can not use the message content.
Selectors are mostly useful for Topics that broadcast a very large number of messages to its subscribers.
They way selectors work depends on the destination type:
*On Queues, only messages that match the selector will be returned. Others stay in the queue (and thus can be read by a MessageConsumer with different selector).
*On Topics, messages that do not match the selector will be ignored as if they have not been published.
In order to create a selection, you need to pass it to the createConsumer or createDurableSubscriber invocation:
Code examples:
Session session = ...
MessageConsumer consumer1 = session.createConsumer(queue,
"(releaseYear < 1980) OR (releaseYear > 1989)");
MessageConsumer consumer2 = session.createConsumer(queue,
"(releaseYear BETWEEN 1980 AND 1989) AND title LIKE 'Michael%'");
MessageConsumer consumer3 = session.createConsumer(queue,
"(releaseYear = 1982) OR (title = 'Thriller')");
MessageConsumer consumer4 = session.createDurableConsumer(queue,
"title IN ('Off the wall', 'Thriller', 'Bad')");
When you create a consumer, you can mention the selector as second argument
session.createConsumer(queue,"destinationInstance IN('a', 'b','c')")
session.setMessageListener(...)
I have a question as regards JMS Queues.
I have implemented a jms sender/reciever using a shared queue as its the only queue avaialbe to me and the only one i can use.
The problem that i am now faced with is that i as this first come first served i cannot guarentee that the messages that i am sending from my producer will be consumed by my consumer and not the other sharing this queue and vice versa. So i am consuming the other apps messages and they are consuming mine.
Is there a way i can just listen for my messages and not consume them from the queue or is this more of a topic implementation?
Or perhaps i can explicitly set an identifier that only my consumer will pick up.
My main code:
public class AsyncReceiver implements MessageListener, ExceptionListener
{
public static void main(String[] args) throws Exception
{
//create queue factory
factory = new TibjmsQueueConnectionFactory(serverUrl);
//create queue connection
queueConn = factory.createQueueConnection(userName, password);
queueConn.setExceptionListener(this);
//create queue session
session = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
//receive message by QueueReceiver
final Queue queue = session.createQueue(queueName);
final QueueReceiver queueReceiver = session.createReceiver(queue);
queueReceiver.setMessageListener(this);
queueConn.start ();
}
You should use JMS selector. Every JMS message can contain properties that you initiate at sender's side.
Message consumer can register to JMS destination (either queue or topic) specifying selector - SQL-like statement that explains which messages does it want to consume. So you can specify your application specific property and then receive relevant messages only.
You could use message selector as shown below
queueReceiver = queueSession.createReceiver(responseQueue, "JMSCorrelationID='"
+ requestMessage.getJMSCorrelationID() +"'");
Here i am using the JMS correlation ID to identify the correct message I need.
Please note that the filter will only work on Message Header and Message properties.
It will not work on the message content.
Details on Message Header & Properties: http://docs.oracle.com/javaee/1.4/tutorial/doc/JMS4.html#wp79367
If you need to filter based on message content, you may have to use QueueSession.MANUAL_ACKNOWLEDGE mode and acknowledge messages that you want. In this case the application has to have the logic to identify messages based on content. Not the ideal design though.
I am receiving messages from aActive MQ queue.
Is there a way to receive a number of messages in one time? or is that have to be done with a loop?
Further more, if i want to take say 30 messages run a procedure, and only if that procedure works return a message.acknowledge(); for all of them.
I mean i dont want to erase those 30 from the queue if the procedure fails.
Thanks.
You'll have to do it in a loop. Usually, it's best to use message-driven beans for consuming messages, but it's not suitable for this case, because they take message by message and you cannot specify the exact number. Thus, use MessageConsumer and manual transactions:
#Resource
UserTransaction utx;
#Resource(mappedName="jms/yourConnectionFactory");
ConnectionFactory cf;
#Resource(mappedName="jms/yourQueue");
Queue queue;
..
Connection conn = null;
Session s = null;
MessageConsumer mc = null;
try {
utx.begin();
conn = cf.createConnection();
s = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE); //TRANSACTIONAL SESSION!
mc = s.createConsumer(queue);
conn.start(); // START CONNECTION'S DELIVERY OF INCOMING MESSAGES
for(int i=0; i<30; i++)
{
Message msg = mc.receive();
//BUSINESS LOGIC
}
utx.commit();
} catch(Exception ex) {
..
} finally { //CLOSE CONNECTION, SESSION AND MESSAGE CONSUMER
}
I don't have any experience in ActiveMQ. But I think in case of queue listeners, basic logic should be the same independent to the queue implementation.
For your first question I don't know any way of retrieving multiple messages from a queue. I think best way would be to fetch it one by one inside a loop.
For your second question, message will not be discarded from the queue till the underlying transaction which read the message commits. So you could read whole bunch of messages in a single transaction and roll it back in case of an error. It shouldn't erase any existing messages from the queue.
May I ask why do you need 30 messages to run a procedure. Usually when we use a queue, each message should be able to process independently.
I am using Active MQ and the Java JMS.
I want to count the number of messages on the queue.
One approach is counting the messeages with a browser:
Queue queue = (Queue) session.createQueue(subject);
QueueBrowser queueBrowser = session.createBrowser(queue);
Enumeration<?> e = queueBrowser.getEnumeration();
int numMsgs = 0;
// count number of messages
while (e.hasMoreElements()) {
// Message m = (Message) e.nextElement();
e.nextElement();
numMsgs++;
}
But for a queue with 5000 pending requests, this only return 500.
Another approach is this (iterate all the messeages in the queue):
Message message= consumer.receive(500);
while(message!= null)
{
if (message instanceof TextMessage)
{
TextMessage textMessage = (TextMessage) message;
// BytesMessage Byte
System.out.println("Received message '"+ textMessage.getText() + "'");
}
if(message!=null)
Messages_list.add(message);
message = consumer.receive(1);
}
But this also dont give the right amount of messages pending.
How can i confidently iterate akk the messages waiting in the queue?
There is a bug in ActiveMQ that is preventing the browse from returning the actual number of messages. In this case the browse is only returning a single page of messages, which is set by the maxPageSize property and documented here: http://activemq.apache.org/per-destination-policies.html
ActiveMQ currently has a bug report on this issue and it is being tracked here: https://issues.apache.org/jira/browse/AMQ-4181. This issue has been resolved and is currently scheduled to be fixed in ActiveMQ 5.8.0.
Since you are using ActiveMQ, you can make use of ActiveMQ's StatisticsPlugin: http://activemq.apache.org/statisticsplugin.html
Similarly, to query the statistics for a destination just send a message to the destination name prepended with ActiveMQ.Statistics.Destination. For example, to retrieve the statistics for a queue whose name is TEST.FOO, send an empty message to the queue named ActiveMQ.Statistics.Destination.TEST.FOO
Specifically, you might be interested in enqueueCount.
I'm omitting example code here, since the example code on the plugin's webpage are concise and good.
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.