jakartaee / messaging

Jakarta Messaging
https://eclipse.org/ee4j/messaging
Other
41 stars 33 forks source link

Allow messages to be delivered asynchronously in batches #36

Open glassfishrobot opened 13 years ago

glassfishrobot commented 13 years ago

It is proposed that the JMS API be extended to allow messages to be delivered to a MessageListener in batches rather than individually as in JMS 1.1.

Currently, messages are delivered asynchronously by calling the javax.jms.MessageListener method onMessage(Message message).

However some applications could process messages more efficiently if they were delivered in batches. Applications would define a new listener class javax.jms.BatchMessageListener with a callback method onMessages(Message[] messages).

It would be necessary to configure this by adding a new method to javax.jms.MessageConsumer:

void setBatchMessageListener(BatchMessageListener listener, int batchSize, long batchTimeOut)

Sets the message consumer's batch message listener. Attempting to set both a message listener and a batch message listener on the same MessageConsumer would cause a javax.jms.IllegalStateException.

Acknowledgement:

glassfishrobot commented 6 years ago
glassfishrobot commented 13 years ago

@glassfishrobot Commented Reported by @nigeldeakin

glassfishrobot commented 13 years ago

@glassfishrobot Commented @nigeldeakin said: Updated description to specify that a new kind of listener would be used BatchMessageListener which was set by calling setBatchMessageListener(listener, batchSize, batchTimeout).

glassfishrobot commented 12 years ago

@glassfishrobot Commented @nigeldeakin said: Corrected formatting errors and typos above.

I considered whether there should be a method setbatchMessageListener(BatchMessageListener listener) which used values of batch timeout and batch size that were set using new setter methods setBatchTimeout and setBatchSize.

I decided that decided that this was not appropriate since

glassfishrobot commented 12 years ago

@glassfishrobot Commented @nigeldeakin said: In order to allow the existing "Chapter 8 API" to use the BatchMessageListener interface it will be necessary to add a new method to javax.jms.Session:

void setBatchMessageListener(BatchMessageListener listener, int batchSize, long batchTimeOut)

This would be optional just as the existing setMessageListener method is.

glassfishrobot commented 12 years ago

@glassfishrobot Commented @nigeldeakin said: I've now updated the javadocs and the draft spec with details of this new feature (these changes are additive, so those docs include other changes).

The updated Javadocs are here: http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar (See two new methods on MessageProducer, two new methods on MessagingContext, and a new interface CompletionListener)

The updated draft spec is here: http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf (All changes are highlighted clearly with changebars. The main changes now are a new BatchMessageListener interface and new methods on MessageConsumer and MessagingContext. I've also added new methods to Session for use with the ConnectionConsumer API)

glassfishrobot commented 12 years ago

@glassfishrobot Commented colincrist said: I'd like to add a comment on a specific use case I've seen from time to time with queues and durable subscriptions - mostly the latter - and I think it probably fits here.

Consider a service (MDB or plain JMS) starting up and there are a bunch of messages on a queue or durable subscription for it to process. The simple way is to begin processing then one by one.

However this can be quite inefficient if the processing for each message is time consuming and there is a big backlog of messages. Often there are many changes in the batch for the same entity (e.g. order/trade etc) and earlier versions of the update messages can either be skipped or merged together to result in a single update to each entity for the batch.

An optimisation is to:

) consumer all the messages available (or in large batches) in a transaction [I've seen this done by going behind the JMS API to JMX or a custom API and get the queue depth or durable subscription depth - often requiring different authentication - ikky] ) pre-process all the messages coalescing or discarding messages no longer relevant. *) process the resulting batch of updates.

Couple of questions:

1) Reading the current version of the spec for batch delivery can you confirm that it is the intention that this pattern can be used? If I were to setBatchMessageListener(foo, 1000, 0) and there were X thousand messages pending then I'd then those messages in batches of 1000 and then very small batch message delivery depending on the implementation/message rate etc after that.

2) There seems to be no matching synchronous Message[] MessageConsumer.receiveBatch(int batchSize, long batchTimeout). Is this intentional and if so what's the rational for not including it?

glassfishrobot commented 12 years ago

@glassfishrobot Commented @nigeldeakin said: @colincrist: Please note that the best place for general discussion is users@jms-spec.java.net

(1) Calling setBatchMessageListener(foo, 1000, 0) would means that the application was requesting messages to be delivered in batches of no more than 1000. A timeout of 0 means that the JMS provider is allowed to delay message delivery as long as it wanted in order to assemble a batch of the required size. I think a shorter timeout than that would almost always be preferable.

So if this was called when there were 3500 messages on the queue, three batches of 1000 would be delivered and then the server would wait, potentially for ever, for a fourth batch to be assembled.

If a smaller tineout were specified (say 1000ms) then the server would wait for 1 second and then deliver a batch of 500.

The JMS provider is allowed to deliver a smaller batch size than is requested, and to use a shorter timeout than that requested. However the basic idea is that specifying a batch size of 1000 means that they application would prefer batches of 1000 if possible. So although a JMS provider could probably legally offer the behaviour you describe, this would be contrary to what is intended.

(2) Yes this was intentional, since in this case an application could assemble a batch of 1000 simply by calling receive() 1000 times, which would not be possible in the async case. However I can see merit in allowing batches to be delivered to sync consumers as well. Watch this space...

glassfishrobot commented 12 years ago

@glassfishrobot Commented @nigeldeakin said: Following discussions on the JSR 343 expert group it is clear that there is insufficient support for this change, so I'm removing all references to batch delivery from JMS 2.0.

There does appear to be some support for looking at this again in the Java EE 8 timescale, when changes to the JCA spec may allow a more generic way of defining async message listeners that does not rely on implementing a specific interface. This would allow the delivery of batches of messages without complicating the API unduly.

We'll look at this again for JMS 2.1. Tagging accordingly.

glassfishrobot commented 13 years ago

@glassfishrobot Commented Issue-Links: blocks JMS_SPEC-56

glassfishrobot commented 7 years ago

@glassfishrobot Commented This issue was imported from java.net JIRA JMS_SPEC-36