The JMS specification defines two different ways of defining message destinations: Queues and Topics. Understanding the behavior of each is vital to implementing messaging within a system and fulfilling any expectations of message availability.
First a quick aside, the purpose of this post is mostly to keep myself from committing the mistakes I made today based upon invalid assumptions regarding the availability messages sent to a queue within an environment with multiple listeners. In a nutshell, I was writing a test to queue up a single message and I have a listener within the test receive the message. For some reason the message was never being received…baffling given the simplicity of the test and the maturity of the code.
Here is the test (ignore that the test is not well written, I just want to quickly test that the code works while I am developing):
I edited this code a bit for simplicity, but in essence a message should be pumped to the console and displayed (real test validates that message was received after x seconds delay). The only problem was I that I was getting nada…note that I am not testing the queuing API itself, I am testing that the strategy will push a message onto the queue without throwing an exception. It’s basically a throwaway test to prove that it works as expected in an integrated environment.
The problem was that the message was never being received by the listener (QueueReceiver is the listener), however other similar tests that are messaging API specific were working as expected. Running through the usual checks turned up nothing. The code simple didn’t work…but only for this test! Swapping out for another queue worked perfectly :(
Fool me once, shame on you. Fool me twice…
So, what was causing the problem? Well it all became very clear once I went back and reflected on the basics of JMS messaging and the differences in how messages are delivered to queues and topics.
The JMS specification supports two models for sending messages: point-to-point for queues and publish and subscribe for topics. In a nutshell, only one consumer of a queue will receive a messaging regardless of the number of consumers; round-robin message dispersal. Whereas a topic broadcasts a copy of the message to every registered consumer.
It turns out out that I had a windows service running that was a consumer of the same queue and It was the first listener, so it always got the first message. The unit test never received a copy because only one message was sent and the consumer on the windows service always pulled it off. This was proved by simply calling publish twice:
This consumer (_receiver) got the second message, because the first one was consumed by the windows service and the next round-robin listener was this unit test. ARGGGHHHH, what a waste of time and brain power!
- Don’t write unit tests with external dependencies and assume they will behave as expected
- Don’t use shared queues for testing
- Don’t forget the difference between queues and topics