In JMS consider the following pseudo-code:
Sender:
QueueSender qs = session.createSender(queue);
int i = 0;
while(i < 10)
{
TextMessage msg = session.createTextMessage();
msg.setText(""+i);
msg.setIntProperty("value", i);
qs.send(msg);
i++;
}
Receiver:
String sel = "value >2";
QueueReceiver qr = session.createReceiver(q,sel);
while(true)
{
TextMessage tm = (TextMessage) qr.receive();
System.out.println(tm.getText);
}
I would have expected the consumer not to consume/print anything becauses the messages he is interested at are blocked by the messages 0,1,2 that are not being pulled by any consumer.
What I see instead is the consumer printing out all the messages selected by its selector...
Is that the correct behaviour of JMS ?
Is that documented somewhere ?
thanks.
I would have expected the consumer not to consume/print anything
becauses the messages he is interested at are blocked by the messages
0,1,2 that are not being pulled by any consumer
This assumption is incorrect. When you use a selector in JMS, the messages that do not satisfy the selector expression will not be delivered to the QueueReceiver. The QueueReciever will continue to read all those messages that satisfy the selector expression.
I believe that your output contains the numbers from 3 - 10. . This is the expected behavior. See the documentation for the createReceiver method.
Related
I have an application with several activeMq queues. I would like to list the messages in them and remove any of them from any of the queues based on the id of the message.
Here is my code so far.
public void killMessage(String id) {
try {
ActiveMQConnection activeMqConnection = (ActiveMQConnection) connectionFactory.createConnection();
activeMqConnection.start();
DestinationSource destinationSource = activeMqConnection.getDestinationSource();
Set<ActiveMQQueue> queues = destinationSource.getQueues();
QueueSession queueSession = activeMqConnection.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE);
for(ActiveMQQueue queue : queues) {
QueueBrowser browser = queueSession.createBrowser(queue);
Enumeration<?> messagesInQueue = browser.getEnumeration();
while (messagesInQueue.hasMoreElements()) {
Message message = (Message) messagesInQueue.nextElement();
System.out.println("Current id: " + message.getJMSMessageID());
if(message.getJMSMessageID().equals(id)){
System.out.println("-----message id found-------");
}
}
}
activeMqConnection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
I iterate through all the queues, then I iterate through all messages in each queue. I even find the message I want to delete, but I cannot find a way to remove it from the queue.
Edit:
I also created a consumer. I am not sure how the consumer should make the messages disappear from the queue. My attempt at it, which have no effect at all, messages remain in the queue, and I get no error message and no exception is thrown which could indicate the consumer did not match a message:
if(message.getJMSMessageID().equals(id)){
System.out.println("-----message id found-------");
MessageConsumer consumer = queueSession.createConsumer(queue, "JMSMessageID='" + id + "'");
consumer.receive();
consumer.close();
}
If you want to use the JMS API to do this then you'll have to create a consumer and use a selector to consume the message with the ID that you want. A queue browser cannot consume messages; it can only browse them.
In the code you pasted you're creating a transacted session which means when you consume the message you'll need to commit the session otherwise the message will never be acknowledged. That said, you're probably better off creating a non-transacted session with AUTO_ACKNOWLEDGE instead.
Also, you probably want to call receive(int) (i.e. with a timeout) so that if the selector can't find the message for some reason your application doesn't just sit there forever waiting on the method to return.
I have a requirement to fetch the pending messages from tibco ems queue. Below is my program using spring jms template. However, I published 5000 messages to queue and tried fetching the count of same with out consuming, and realized it took nearly 20 minutes to browse and get the count. Please advise on any performance improvement here or any other better way to get the pending message count
jmsTemplate.execute(new SessionCallback<QueueBrowser>() {
public QueueBrowser doInJms(Session session) throws JMSException {
javax.jms.Queue queue = session.createQueue(queueName);
QueueBrowser browser = session.createBrowser(queue);
Enumeration messages = browser.getEnumeration();
int num = 0;
while(messages.hasMoreElements()) {
messages.nextElement();
num +=1;
LOG.info("num={}",num);
}
return null;
}
}, true);
From EMS 8.3 samples:
javax.jms.QueueBrowser browser = session.createBrowser(queue);
Enumeration msgs = browser.getEnumeration();
int browseCount=0;
while (msgs.hasMoreElements())
{
message = (javax.jms.Message)msgs.nextElement();
System.err.println("Browsed message: number="+message.getIntProperty("msg_num"));
browseCount++;
}
I've got this scenario:
a JMS message elaboration via an MDB might fail (throws a RuntimeException in this case)
the message should be redelivered, though after a delay (ideal, but not strictly necessary: after an increasing delay depending on the number of fails)
after x failures, the message should be disregarded and never sent again
Right now, the behaviour I have is that the failed message is redelivered instantly for 10 times, and I haven't been able to customize this.
Is there a way I can achieve this via #JMSdefinition (or other annotations as well) or setting the correct properties in the message? If so, how to do?
You can schedule the message with _AMQ_SCHED_DELIVERY property:
Queue q = (Queue) ServiceLocator.getInstance().getDestination("QUEUE");
QueueConnectionFactory factory = (QueueConnectionFactory) ServiceLocator.getInstance().getConnectionFactory(
"java:/ConnectionFactory");
QueueConnection connection = factory.createQueueConnection();
QueueSession session = null;
QueueSender sender = null;
session = connection.createQueueSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
sender = session.createSender(q);
ObjectMessage msg = session.createObjectMessage();
if (redelivedCount > 0) {
msg.setIntProperty("redelivedCount", redelivedCount);
// schedule to run in 10 secs
msg.setLongProperty("_AMQ_SCHED_DELIVERY", System.currentTimeMillis() + 10000);
}
msg.setStringProperty("action", action);
msg.setObject(params);
sender.send(msg);
I have a method annotated with #ServiceActivator("CH1"), where "CH1" definition is:
#Bean(name = "CH1")
MessageChannel ch1() {
return new PublishSubscribeChannel
}
and other PollableChannels publishing to this channel via
#BidgeTo(value = "CH1", poller = #Poller("myPoller"))
Things seem to work fine most of the time; however, seemingly randomly the message handler unsubscribes from "CH1" and I see in the logs:
[DEBUG] (pool-2-thread-1) org.springframework.integration.dispatcher.BroadcastingDispatcher: No subscribers, default behavior is ignore
Now I know I can change the minSubscribers but I don't get why things seem to randomly unsubscribe? After this error it will go back to handling some messages fine. Does a message handler unsubscribe while handling messages or if the executor being used is full? I see no errors associated with this in the log nor and unsubscribe or update to subscriber counts to "CH1" in the logs.
That does not make sense. Please, share some test-case to reproduce from the Framework perspective.
The source code on the matter looks like:
if (dispatched == 0 && this.minSubscribers == 0 && logger.isDebugEnabled()) {
if (sequenceSize > 0) {
logger.debug("No subscribers received message, default behavior is ignore");
}
else {
logger.debug("No subscribers, default behavior is ignore");
}
}
where we can go to the sequence == 0 only in case of:
Collection<MessageHandler> handlers = this.getHandlers();
if (this.requireSubscribers && handlers.size() == 0) {
throw new MessageDispatchingException(message, "Dispatcher has no subscribers");
}
int sequenceSize = handlers.size();
Only the clue that your subscribers unsubscribes somehow...
I see that you have a DEBUG for your CH1, so would you mind to share DEBUG logs for entire org.springframework.integration when you see that error.
EDIT
Also note that whenever a subscriber is added/removed (e.g. when a consuming endpoint is started/stopped), you will see this log message...
if (logger.isInfoEnabled()) {
logger.info("Channel '" + this.getFullChannelName() + "' has " + counter + " subscriber(s).");
}
(when logging with at least INFO logging).
I list down queues and messages from each queue. The following is my code. But, QueueBrowser does not retrieve messages correctly.
Let's say, I have a queue named TestQueue which has 1000 message.
first time i run my program it shows only 200 messages.
second - 400
third - 600
forth - 800
fifth - 1000
Can you tell me how to fix this problem?
ConnectionFactory out = new ActiveMQConnectionFactory("tcp://localhost:61616?jms.prefetchPolicy.all=10000");
ActiveMQConnection connection = (ActiveMQConnection) out.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Set<ActiveMQQueue> amqs = connection.getDestinationSource().getQueues();
Iterator<ActiveMQQueue> queues = amqs.iterator();
while ( queues.hasNext() )
{
ActiveMQQueue queue_t = aqueues.next();
String q_name = queue_t.getPhysicalName();
List<ActiveMQMessage> msgList = ((ActiveMQSession) session).getUnconsumedMessages();
System.out.println( "\nQueue = " + q_name);
QueueBrowser queueBrowser = session.createBrowser(queue_t);
Enumeration e = queueBrowser.getEnumeration();
int numMsgs = 0;
while(e.hasMoreElements())
{
Message message = (Message) e.nextElement();
numMsgs++;
}
System.out.println("No of messages = " + numMsgs);
queueBrowser.close();
}
session.close();
connection.close();
From the javax.jms.QueueBrowser API:
Messages may be arriving and expiring while the scan is done. The JMS API does not require the content of an enumeration to be a static snapshot of queue content. Whether these changes are visible or not depends on the JMS provider.
Have you tried specifying the prefetch policy?
Just connect using JMX to Broker (use jconsole for example). On specific queue set MaxPageSize properties more than 200 then you can list more messages.