My JMS consumer produces any number of messages on a JMS queue during the day. As soon as a
message arrives it goes to message listener. If in between I need some other message comes, it goes to another message listener does not wait for first one?
As per my understanding here I need to create two consumer(assume i want to process 2 message concurrently) each having its own session. Both consumer can use the same message listener. Right?
I am not sure if I can achieve it with single consumer but can I with multiple listeners?
something like this Single queue: concurrent message processing with multiple consumers
Per the JMS documentation #bgth cites, multiple MessageListeners in a single session will not provide concurrency:
"The session used to create the message consumer serializes the execution of all message listeners registered with the session. At any time, only one of the session’s message listeners is running"
For concurrency, you need multiple sessions and multiple consumers in separate threads. You can reuse the same MessageListener in this case, but it must be threadsafe.
Related
Java & RabbitMQ here. I need to implement sort of a poison pill pattern where, upon handling a particular message, the consumer needs to cancel itself and stop receiving/handling any further messages. Full stop and clean up. The message kills the consumer and releases the thread, memory, etc.
I see consumers have a handleCancel method that they can implement to respond to cancellation commands from the outside, but how do I handle a poison pill message inside a consumer that tells the consumer to fall over dead?
I don't think RabbitMQ handles this scenario for some reason.
My solution which appears to be working:
Implement a stateful consumer that exists in one of two states: Processing (default) and Terminating
When its in the Processing state it consumes and handles messages off the queue like normal. When it receives the magical poison pill (perhaps a value in the message header/properties, or maybe a specific value in the message itself) it sets its status to Terminating and does not process the message. It also uses an async event bus to send a custom ShutdownConsumerEvent to an external handler. This event is instantiated with both the channel and consumerTag sent to the consumer (e.g. ShutdownConsumerEvent event = new ShutdownConsumerEvent(channel, consumerTag);)
Any more messages the consumer receives while in the Terminating state get republished to the queue, with ACKs enabled so we don't lose them and have pseudo-transactionality
When the external ShutdownConsumerSubscriber (a registered handler to receive ShutdownConsumerEvents) receives the command to shut down the consumer, it does this by issuing a channel.basicCancel(consumerTag)
After reading some document of JMS, I totally puzzled by the phrase synchronous and asynchronouns.
See this page: http://docs.oracle.com/cd/E19798-01/821-1841/bncdq/index.html
Synchronous
You use the receive method to consume a message synchronously.
You can use this method at any time after you call the start method:
connection.start();
Message m = consumer.receive();
connection.start();
Message m = consumer.receive(1000); // time out after a second
To consume a message asynchronously, you use a message listener, described in the next section.
Asynchronous
JMS Message Listeners
A message listener is an object that acts as an asynchronous event handler for messages. This object implements the MessageListener interface, which contains one method, onMessage. In the onMessage method, you define the actions to be taken when a message arrives.
You register the message listener with a specific MessageConsumer by using the setMessageListener method. For example, if you define a class named Listener that implements the MessageListener interface, you can register the message listener as follows:
Listener myListener = new Listener();
consumer.setMessageListener(myListener);
I have two questions:
As what I understood, the nature of JMS is asynchronous. Producer publishes messages to the queue/topic, it doesn't need to wait consumer. This is asynchronous behaviour. How can it be "synchronous"?
If the "mesageListener" is asynchronous, but in my test with spring-jms, I found it always running in a thread. That means, if I write Thread.sleep(2000) in onMessage, it have to be wait 2 seconds before processing next message. Is it "asynchronous"?
If you understand it better like this, consumer.receive() uses a pull model: you read from a queue and are blocked waiting for this message until it comes, or some timeout has elapsed.
Using a listener uses a push model: you register a listener and, when a message comes in, the listener is called, in a separate thread.
Everything is done in a thread in Java, and the listener call is no exception. Whether the listener message handling prevents the processing of other messages in the queue depends on how many threads are dedicated to message processing. If you configure Spring to use a pool of 5 threads to process messages asynchronously, then 5 listeners will be able to process messages in parallel.
Like I understand this:
asynchronous - MessageListener: Use this on a server that listens to a queue. When a message arrives, then deal with it immediately. The server keeps listening to this queue.
synchronous - consumer.receive(1000): Use this on a client applications that now and then needs to check if a message is intend for this client. Example: poll every 60 seconds. This only opens a connection to the server shortly. The 1000 milliseconds will keep this connection open. If a message arrives within these 1000 milliseconds, then the message is consumed and the connection is closed.
You are looking at it end-to-end: from publisher to the consumer. Yes, it is asynchronous delivery from publisher to consumer irrespective of Sync/Async consumer. However Sync/Async in your question is for consumer only, i.e from the JMS broker (eg: ApacheMQ) to the consumer. As others have pointed out, Sync consumers pull messages sequentially from the broker and are waiting for messages. Async consumers register a callback where messages pushed to them (onMessage). Async consumers can go about doing other things while these messages are delivered to them asynchronously from the JMS broker.
I understand synchronous/asynchronous differently.
Synchronous: Caller(Sender) has to wait till the response from consumer has been received(till the time-out) -- request/reply pattern
Asynchronous: Caller(Sender) just post message and continue with its work, while the consumer processes as soon as the message reaches it -- one way request
Any MOM(Message Oriented Middle ware) follows service activator pattern which promotes asynchronous communication. One of my project has implemented a framework around JMS to make communication really synchronous.
Any message has 2 parts.
a. Metadata attributes
b. Payload
Set attribute "reply-to-queue" to a randomly generated value
Make sure the MOM framework creates temporary queue with name from #2
Make sure the sender spawns thread, which listens to temporary queue created in #3
Publish message and block sender till it receives message to temporary queue
Make sure the consumer intercepts "reply-to-queue" header and publishes response to it
This is one of the ways to make MOM based communication acts like synchronous. You may find other implementations like request-reply mechanism.
There are two threads in my application - one that asynchronously reads the messages from MQ queue and send them to the processing unit and a second that retrieves information from processing unit and puts the related messages on a sender queue. The problem is, next messages is retrieved and send to the processing unit before the previous message output thread has finished and this is not correct from application point of view. Since the messages may be found on queue at any time to be processed, it is not desirable to read messages synchronously.
I know that I could introduce another queue to keep messages until ready to be processed but are there any MQ setup-related solutions that I could use instead? It seems to me like a very common setup.
Thank you in advance for advice/help.
This is basically a synchronisation problem. I would have setup an signalling mechanism where message listener sends the message received from MQ to processing unit and waits on an event. The output thread after sending the message to an output queue signals the event. Once signalled the message listener waits for the next message from queue.
I could understand the question to some extent ... It looks like all you want to do to is to hold the message listener for sometime until another activity is completed. The message listener can use a selector which gets messages which have a property state=READY. When the output thread completes it can get a message from queue and set the state to READY. By default if this property is not set on the message the message listener won't pick that message.
I want to concurrently consume jms messages from multiple queues. All the messages should go to the DB after long running processing and I have no right to lose them.
Question: Is it possible to save messages for future acknowledgement and call oldMessage.acknowledge() when another message is being processed?
My first guess is that this is impossible since it is deep in the jms processing unit and I have to process message and acknowledgement within an onMessage(...) method.
Second guess is to split onMessage() concurrently and allow long running processing for many messages. But this is not a good option since I have to ensure that all messages are coming ordered!
2nd question: Is there any way to ensure the incoming order while concurrency processing?
1: JMS has a flag on Session that is *CLIENT_ACKNOWLEDGE* you can see it here. I never used it but seems to do what you want.
2:
2.1: You have N consumers for the same queue: You can explore the Exclusive Consumer that some implementations have support. (for AtiveMQ: here).
2.2 You have 1 consumer per queue but you want to order all messages from all queues.
You can use the concept of an ordered SlackBuffer.
You can explore another possibilities like: Redirect all messages to an output queue that maintains the order of messages and you will only consume messages from that single output queue. The order of messages and the redirection are accomplished by the MQ server. It is only a valid idea if you can control the MQ server.
I hope this can help
Is there a message queue implementation that allows breaking up work into 'batches' by inserting 'message barriers' into the message stream? Let me clarify. No messages after a message barrier should be delivered to any consumers of the queue, until all messages before the barrier are consumed. Sort of like a synchronization point. I'd also prefer if all consumers received notification when they reached a barrier.
Anything like this out there?
I am not aware of existing, widely-available implementations, but if you'll allow me I'd propose a very simple, generic implementation using a proxy, where:
producers write to the proxy queue/topic
the proxy forwards to the original queue/topic until a barrier message is read by the proxy, at which point:
the proxy may notify topic subscribers of the barrier by forwarding the barrier message to the original topic, or
the proxy may notify queue subscribers of the barrier by:
periodically publishing barrier messages until the barrier has been cleared; this does not guarantee that all consumers will receive exactly one notification, although all will eventually clear the barrier (some may receive 0 notifications, others >1 notifications -- all depending on the type of scheduler used to distribute messages to consumers e.g. if non-roundrobin)
using a dedicated topic to notify each consumer exactly once per barrier
the proxy stops forwarding any messages from the proxy queue until the barrier has been cleared, that is, until the original queue has emptied and/or all consumers have acknowledged all queue/topic messages (if any) leading up to the barrier
the proxy resumes forwarding
UPDATE
Thanking Miklos for pointing out that under JMS the framework does not provide acknowledgements for asynchronous deliveries (what is referred to as "acknowledgements" in JMS are purely a consumer side concept and are not proxiable as-such.)
So, under JMS, the existing implementation (to be adapted for barriers) may already provide application-level acknowledgements via an "acknowledgement queue" (as opposed to the original queue -- which would be a "request queue".) The consumers would have to acknowledge execution of requests by sending acknowledgement messages to the proxy acknowledgement queue; the proxy would use the acknowledgement messages to track when the barrier has been cleared, after having also forwarded the acknowledgement messages to the producer.
If the existing implementation (to be adapted for barriers) does not already provide application-level acknowledgements via an "acknowledgement queue", then you could either:
have the proxy use the QueueBrowser, provided that:
you are dealing with queueus not events, that
you want to synchronize on delivery not acknowledgement of execution, and
it is OK to synchronize on first delivery, even if the request was actually aborted and has to be re-delivered (even after the barrier has been cleared.) I think Miklos already pointed this problem out IIRC.
otherwise, add an acknowledgment queue consumed by the proxy, and adapt the consumers to write acknowledgements to it (essentially the JMS scenario above, except it is not necessary for the proxy to forward acknowledgement messages to the producer unless your producer needs the functionality.)
You could achieve this using a topic for the 'Barrier Message' and a queue for the 'batched items' which are consumed with selective receivers.
Publishing the Barrier Message to a topic ensures that all consumers receive their own copy of the Barrier Message.
Each consumer will need two subscriptions:
To the Barrier Topic
A selective receiver against the batch queue, using selection criteria defined by the Barrier Message.
The Barrier Message will need to contain a batch key that must be applied to the queue consumers selection criteria.
e.g. batchId = n
or JMSMessageID < 100
or JMSTimestamp < xxx
Whenever a barrier message is received,
the current queue consumer must be closed
the queue selection criteria must be modified using the content of the Barrier Message
a new selective consumer must be started using the modified selection criteria
If you are going to use a custom batch key for the selection criteria such as 'batchId' above, then the assumption is that all message producers are capable of setting that JMS property or else a proxy will have to consume the messages set the property and republish to the queue where the selective consumers are listening.
For more info on selective receivers see these links:
http://java.sun.com/j2ee/1.4/docs/api/javax/jms/Message.html
http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/jms/QueueSession.html#createReceiver(javax.jms.Queue,%20java.lang.String)