问题
I have 2 simple EJB beans. The first one is a timer method that is called every second. In this method I add 10 random messages to a TestQueue.
@Singleton
@Startup
public class Timer {
@Inject
private JMSContext context;
@Resource(mappedName = "java:/jms/queue/TestQueue")
private Queue queue;
@Schedule(hour = "*", minute = "*", second = "*/1", persistent = false)
@AccessTimeout(unit = TimeUnit.DAYS, value = 1)
public void addToQueue() {
for(int i = 0; i<30; i++)
context.createProducer().send(queue, "msg " + (new Random().nextInt(100)));
printQueueSize();
}
public void printQueueSize() {
QueueBrowser qb = context.createBrowser(queue);
Enumeration enumeration = null;
try {
enumeration = qb.getEnumeration();
} catch (JMSException e) {
e.printStackTrace();
}
int size = 0;
while(enumeration.hasMoreElements()) {
enumeration.nextElement();
size++;
}
System.out.println("Queue size: " + size);
}
}
Second bean is a MDB consumer. I put Thread.sleep(100) to simulate long running task and make sure that there are some messages in TestQueue.
@MessageDriven(
activationConfig = {
@ActivationConfigProperty(propertyName = "destination", propertyValue = "java:/jms/queue/TestQueue"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "maxSession", propertyValue = "1")
})
public class Consumer implements MessageListener {
@Override
public void onMessage(Message msg) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The problem is that console output shows:
15:06:29,006 INFO [stdout] (EJB default - 9) Queue size: 0
15:06:30,006 INFO [stdout] (EJB default - 10) Queue size: 0
15:06:31,009 INFO [stdout] (EJB default - 1) Queue size: 0
etc.
but in the wildfly admin console I can see that there are more and more messages every second:
The question is, why the QueueBrowser return empty Enumeration? Is it a bug in HornetQ implementation or there is some reason for that?
回答1:
Although this will not answer your question, I will show how I get the queue size in HornetQ, in an EJB Service:
InitialContext initialContext = null;
try {
// Step 1. Create an initial context to perform the JNDI lookup.
initialContext = getContext();
// Step 2. Perfom a lookup on the queue
Queue queue = (Queue) initialContext.lookup("jmx/queue/YOUR_QUEUE_NAME");
// Step 7. Use JMX to retrieve the message counters using the
// JMSQueueControl
ObjectName on = ObjectNameBuilder.DEFAULT
.getJMSQueueObjectName(queue.getQueueName());
JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL("service:jmx:http-remoting-jmx://localhost:9990"), new HashMap<String, Object>());//this is the URL for WildFly 8.2 (should work for all 8.X)
MBeanServerConnection mbsc = connector.getMBeanServerConnection();
JMSQueueControl queueControl = MBeanServerInvocationHandler.newProxyInstance(mbsc, on, JMSQueueControl.class, false);
// Step 8. List the message counters and convert them to
// MessageCounterInfo data structure.
String counters = queueControl.listMessageCounter();
MessageCounterInfo messageCounter = MessageCounterInfo.fromJSON(counters);
queueControl.getConsumerCount();//this returns consumer count
queueControl.getMessagesAdded();//returns messages added from the last time we checked
queueControl.isPaused();//prints out, whether the queue is paused (you can stop a queue from being processed e.g. from JMX)
queueControl.getMessageCount();//message count so far
} finally {
// Step 17. Be sure to close our JMS resources!
if (initialContext != null) {
initialContext.close();
}
}
回答2:
printQueueSize()
is returning zero because you are calling it from within addToQueue()
.
Your messages are not on the queue yet because the transaction that was started just prior to entering addToQueue()
will not be committed until the addToQueue()
invocation returns (without errors).
JMS operations are transactional.
回答3:
I was banging my head against this issue for days and finally found out that in our case, it was that the queue was configured to be transactional
.
This means that according to JMS 2 specs, the messages are consumed and put into a transaction at the Consumer
side, so they are not contained in the Queue anymore, but also don't show up anywhere else, it's like a transparent buffer.
see JMS 2 Session API docs:
A session may be specified as transacted. Each transacted session supports a single series of transactions. Each transaction *groups a set of message sends* and a *set of message receives* into an atomic unit of work. In effect, transactions organize a session's *input message stream* and output message stream into series of atomic units. When a transaction commits, its atomic unit of input is acknowledged and its associated atomic unit of output is sent. If a transaction rollback is done, the transaction's sent messages are destroyed and the session's input is automatically recovered.
The content of a transaction's input and output units is simply *those messages that have been produced* and consumed within the session's current transaction.
Simply setting the attribute transaction
to none
in Wildfly's config (usually standalone-full.xml
) solved the issue:
pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" transaction="none"
来源:https://stackoverflow.com/questions/31476843/jms-2-0-queuebrowser-on-wildfly-does-not-return-messages