users@jms-spec.java.net

[jms-spec users] [jsr343-experts] Re: Re: (JMS_SPEC-43) New API to send a message with async acknowledgement from server

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Fri, 13 Jul 2012 10:22:40 +0100

On 13/07/2012 08:08, Rüdiger zu Dohna wrote:
> I'm very much in favor of adding the message to the onException method, but that would be an incompatible change,
> wouldn't it?

Not yet! CompletionListener (which is called when an async send completes or fails) will be new in JMS 2.0, so we can
change it to anything we like :-)

Nigel

>
> On 2012-07-12, at 20:06, Nigel Deakin wrote:
>
>> On 27/06/2012 11:04, Nigel Deakin wrote:
>>> I sent an email on 25th May which described various clarifications in the definition of this new feature and which
>>> proposed a number of restrictions. I have received no comments from the Expert Group. However I have received a lot
>>> of feedback from within Oracle (where's we're thinking of how to implement it in the RI and other products) and am
>>> now proposing the following modified text. Please give your comments by the end of *Friday 6th July.*
>>>
>> I haven't had much feedback on this, with the only doubts coming from Chris Barrow who wondered whether these
>> proposals were "babysitting" the developer too much, which was followed by a comment from Rüdiger who thought they
>> weren't. Given the fact that there is clear support for this feature as a whole I think we should proceed with these
>> detailed changes. If you object say now. I'll draft the actual spec changes shortly.
>>
>> A change that seems to have got lost in the various emails on this subject is a change that I think is needed to the
>> CompletionListener API. This is currently:
>>
>> public interface CompletionListener {
>>
>> /**
>> * Notifies the application that the message has been successfully sent
>> *
>> * @param message the message that was sent.
>> */
>> void onCompletion(Message message);
>>
>> /**
>> * Notifies user that the specified exception was thrown while attempting to send the message
>> *
>> * @param exception the exception
>> */
>> void onException(Exception exception);
>> }
>>
>> For consistency I think we should pass the Message into the onException method as well. This is needed to allow the
>> exception handling method to know which message caused the exception. So the method signature would change to
>>
>> void onException(Message message, Exception exception);
>>
>> I think this corrects a mistake and is not controversial, but if you have any comments please let me know.
>>
>> Nigel
>>
>>> The key changes compared with my previous email are:
>>>
>>> * I've dropped my suggestion to pass in a messageID rather than a Message to the CompletionListener. I'll stick to
>>> the original proposal to pass in the Message itself.
>>>
>>> * I've dropped my proposal that the send() call be required to set the message header fields that are defined in
>>> the spec as being set by the "JMS provider send method" before returning. These are the JMSDestination,
>>> JMSDeliveryMode, JMSExpiration, JMSDeliveryTime, JMSPriority, JMSMessageID and JMSTimestamp header fields. This
>>> is because this would cause difficulties for providers which generate some of these values on the server. For
>>> reasons of consistency the same will apply for the optional message properties JMSXUserID, JMSXAppID,
>>> JMSXProducerTXID and JMSXConsumerTXID. These headers must be set by the time the success callback is performed.
>>>
>>> * A new comment has been added to clarify that the application is not required to wait for an asynchronous send to
>>> complete before sending a subsequent message.
>>>
>>> * Since the JMS provider will be setting these message header fields in a separate thread, after the asynchronous
>>> send method has returned the application must not attempt to read the message until the send is complete.
>>> Applications which do so must receive an exception.
>>>
>>> * In theory this means that it would be safe for the application to send a Message object a second time so long as
>>> the previous send had completed. However if this were permitted there is a danger of a developer writing an
>>> application which works when acks are fast but which throws exceptions when acks are slow. I have therefore
>>> proposed that we simply state that an application uses an async send to send a message it must not attempt to
>>> change the state of the message or send the message a second time, either using an asynchronous or normal send
>>> operation. If the application attempts to do this the JMS provider will throw an exception.
>>>
>>> * I have changed the proposed behaviour of close(). My previous proposal was that if close() was called then there
>>> is no requirement for the JMS provider to block until any incomplete send operations have completed. This would
>>> have interfered with connection pooling. It would also have made to raised other issues which would have needed
>>> clarification. To keep things simple I am now proposing that close() should block until any incomplete send
>>> operations have completed. This makes it consistent with commit() and rollback() for transacted sessions.
>>>
>>> * I have clarified that completion listener callbacks for a given session should be serialised and take place in
>>> the same order as the corresponding call to the async send method.
>>>
>>>
>>> *Proposed new description of this feature*
>>>
>>> The following description of this feature will be added to the spec and javadocs.
>>>
>>> This method is provided to allow the JMS provider to perform part of the work involved in sending a message in a
>>> separate thread, allowing the application to do something else whilst this is happening. JMS refers to this as
>>> an "asynchronous send". When the message has been successfully sent the JMS provider invokes a callback method
>>> on an application-specified CompletionListener object. Only when that callback has been invoked can the
>>> application be sure that the message has been successfully sent with the same degree of confidence as if a
>>> normal synchronous send had been performed. An application which requires this degree of confidence must
>>> therefore wait for the callback to be invoked before continuing.
>>>
>>> The following information is intended to give an indication of how an asynchronous send would typically be
>>> implemented.
>>>
>>> In some JMS providers, a normal synchronous send involves sending the message to a remote JMS server and then
>>> waiting for an acknowledgement to be received before returning. It is expected that such a provider would
>>> implement an asynchronous send by sending the message to the remote JMS server and then returning without
>>> waiting for an acknowledgement. When the acknowledgement is received, the JMS provider would notify the
>>> application by invoking the onCompletion method on the application-specified CompletionListener object.
>>>
>>> In those cases where the JMS specification permits a lower level of reliability, a normal synchronous send might
>>> not wait for an acknowledgement. In that case it is expected that an asynchronous send would be similar to a
>>> synchronous send: the JMS provider would send the message to the remote JMS server and then return without
>>> waiting for an acknowledgement. However the JMS provider would still notify the application that the send had
>>> completed by invoking the onCompletion method on the application-specified CompletionListener object.
>>>
>>> It is up to the JMS provider to decide exactly what is performed in the calling thread and what, if anything, is
>>> performed asynchronously, so long as it satisfies the following requirements.
>>>
>>> Quality of service
>>>
>>> * After the send operation is complete, which means that the message has been successfully sent with the same
>>> degree of confidence as if a normal synchronous send had been performed, the JMS provider must invoke the
>>> completion listener. The completion listener must not be invoked earlier than this.
>>>
>>> Message order
>>>
>>> * If the same MessageProducer or JMSContext is used to send multiple messages then JMS message ordering
>>> requirements (see section 4.4.10.1 "Order of message receipt) must be satisfied. This applies even if a
>>> combination of synchronous and asynchronous sends have been performed. The application is not required to
>>> wait for an asynchronous send to complete before sending the next message.
>>>
>>> Close, commit or rollback
>>>
>>> * If the session is transacted (uses a local transaction) then when commit() or rollback() is called the JMS
>>> provider must block until any incomplete send operations have been completed and all callbacks have returned
>>> before performing the commit or rollback.
>>>
>>> * If close() is called (on the MessageProducer, Session, Connection or JMSContext object) then the JMS
>>> provider must block until any incomplete send operations have been completed and all callbacks have returned
>>> before closing the object and returning.
>>>
>>> Restrictions on usage in Java EE
>>>
>>> * An asynchronous send is not permitted in a Java EE EJB or web container
>>>
>>> Message headers
>>>
>>> * The JMS specification defines a number of message header fields and JMS-defined message properties of the
>>> specified Message which must be set by the "JMS provider send method" (see section 3.4.11 "How message
>>> header values are set" and 3.5.9 "JMS defined properties"). This does not apply if the send is asynchronous.
>>> These fields and properties must however be set before the CompletionListener's onCompletion method is
>>> invoked. If the CompletionListener's onException method is called then the state of these message header
>>> fields and properties is undefined
>>>
>>> Restrictions on threading
>>>
>>> * Applications that perform an asynchronous send must confirm to the threading restrictions defined in section
>>> 4.4.6. "Conventions for using a session". This means that the session may be used by only one thread at a time.
>>>
>>> * Setting a completion listener does not cause the session to be dedicated to the thread of control which
>>> calls the completion listener. The application thread may therefore continue to use the session after
>>> performing an async send. However the CompletionListener's callback methods must not use the session if an
>>> application thread might be using the session at the same time.
>>>
>>>
>>> Use of the CompletionListener by the JMS provider
>>>
>>> * A session will only invoke one CompletionListener callback method at a time. For a given MessageProducer or
>>> JMSContext, callbacks will be performed in the same order as the corresponding calls to the async send method.
>>>
>>> * A JMS provider must not invoke the CompletionListener from the thread that is calling the async send method.
>>>
>>> * An application which do not need to receive notifications when the send has completed or has failed may
>>> supply a null CompletionListener. This does not remove the requirement for the close(), commit() or
>>> rollback() methods to block until any incomplete send operations have been completed.
>>>
>>> Restrictions on the use of the Message object
>>>
>>> * Applications which perform an asynchronous send must take account of the restriction that a Message object
>>> is designed to be accessed by one logical thread of control at a time and does not support concurrent use.
>>> See section 2.8 "Multi-threading".
>>>
>>> * After the send method has returned, the application must not attempt to read the headers, properties or
>>> payload of the Message object until the CompletionListener's onCompletion or onException method has been
>>> called. This is because the JMS provider may be modifying the Message object in another thread during this
>>> time. The JMS provider must throw a JMSException or JMSRuntimeException (depending on the method signature)
>>> if the application attempts to read the Message in such a case.
>>>
>>> * After the send method has returned the application must not attempt to change the state of the message or
>>> send the message a second time, either using an asynchronous or normal send operation. This applies even
>>> after the CompletionListener's onCompletion or onException method has been called. Even though it would be
>>> theoretically possible to allow the Message object to be re-used after the CompletionListener's onCompletion
>>> or onException method has been called, such use is not allowed to avoid an application being created which
>>> succeeds when callbacks were fast and which fails when callbacks are slow
>>>
>>> Nigel
>