Odd behavior with JMS QueueBrowser in 7.1.1.Final
ftg314159 May 10, 2013 9:48 AMI'm seeing some very odd and unpredictable behavior using an application client with JBoss JMS. Searches have found similar reports by others both here and elsewhere, but either the circumstances don't match, they involve coding error I'm not making, or they're unanswered.
Environment:
JBoss is running unchanged as shipped and installed, with the exception of having added a user with a guest role to allow my application to access the predefined testQueue. There is no application code running in JBoss; the application is an external POJO.
Synopsis:
After populating the queue with a set of messages, creating a QueueBrowser, and using getEnumeration() to access the messages works perfectly. But if, while the QueueBrowser is open, I access the first message in the enumeration via nextElement() and then do a receive() to receive that message, the receive() works but the enumeration suddenly has no more elements. If I do another getEnumeration(), I get an empty enumeration. If I restart the application, I get the next message in the queue, and the same behavior (current enumeration and any new enumeration is now empty). Moreover, if I run the application several times in quick succession, the initial executions may get no messages at all, and then suddenly messages are seen.
Background (not critical, can be skipped):
I'm converting an application to JMS from another in-house messaging system that, in JMS terms, allows selective acknowledgment of messages, i. e. if you receive a bunch of messages without acknowledging them, you can acknowledge older ones without implicitly acknowledging all later ones, as happens with JMS.
To replicate this behavior, I decided to "deliver" messages to the application by using a QueueBrowser and getEnumeration(). As I retrieve messages from the enumeration, I maintain a LinkedHashMap which keys the message ID to a Boolean indicating whether the application has "released" the message, and I deliver the message payload to the application. When the application "releases" a message, I mark the associated entry in the linkedHashMap as true, and then iterate through the map, doing a receive() with AUTO_ACKNOWLEDGE for each released message, removing the entry from the map, until I hit one which has not yet been released. The intent is to acknowledge and delete messages which the application has fully consumed, while leaving any later messages intact. If the application releases messages out of order, the later released messages will not be received from the queue until such time as the application has released all older messages.
Testing Results:
In addition to the processing described above, I've tried several variations.
I've tried getting a new enumeration every time I do a series of receive()s - no effect.
I've tried closing and recreating the QueueBrowser after every series of receive()s - no effect.
However, I have found a workaround. If I open *two* separate connections, each with its own session, and use one for the QueueBrowser and the other to do the receive()s, it works perfectly.
If I change the workaround to use two separate sessions on the *same* connection, the first nextElement() returns the first message, but the receive() for that message never returns, i. e. JMS believes the queue is empty.
I'm ready to enter a JIRA with a reproducible case, but I wanted to check here first to be sure that what I'm doing is legal and expected to work in JMS. I wish I could debug this here, but unfortunately 7.1.1.Final ships with HornetQ 2.2.13, and the source for this is no longer available on the HornetQ download site, just 2.2.14 and much older ones. The HornetQQueueBrowser source code seems to have changed enough that the debugger claims that most places I want to stop are not breakpointable lines.