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: Thu, 28 Jun 2012 12:05:11 +0100

Chris,

Again, thank you for your (very clearly-written) comments. I think all your comments relate to aspects to which there
isn't a clear-cut answer. I'd welcome other comments on these topics before I make a final proposal.

On 27/06/2012 21:51, Chris Barrow wrote:
> Hi Nigel,
>
> I am not on the experts list, but I hope you don't mind if I give some feedback. I like most of what you are
> proposing, but do have a couple of comments, mainly based on the principle that rules imposed by the spec should be
> both /necessary /and sufficient.
>
> _1. Restrictions on the use of the Message object_ (3rd bullet point):
>
> o Instead of making it forever disallowed to mutate or (re)send a Message once it's been sent asynchronously,
> why not simply state it's not allowed until the CompletionListener's onCompletion or onException method has
> been called? That would be consistent with the second bullet point, the rule about reading the message.
> Basically I don't see why the two need to be different. The argument about avoiding an application being
> created which succeeds when callbacks are fast and which fails when callbacks are slow is not compelling in my
> opinion. It's not the spec's job to babysit application writers, it is sufficient to warn them, as it does.
> Moreover, the argument would presumably apply to reading message properties too.
>

I agree that my proposal that an application will be forbidden from mutating or re-sending a message in perpetuity after
an async send goes further than is strictly necessary. As I said, it was to make it easy to prevent programmers from
accidentally writing bad code though this isn't something I feel strongly about. Your remark that it's not the spec's
job to babysit application writers is a valid one. Does anyone else have any comments on this?

> o Either way, the spec needs to define what the behavior is if the rule (for mutating or sending) is violated
> (as is done in the second bullet point about reading).
>
> _2. Restrictions on the use of the Message object vs. Restrictions on threading_
> I find it interesting the spec is mandating that providers detect and prevent thread violations on the Message object
> but not on the Session object. Is this just because of the risk that such checks might break existing JMS 1.1
> applications? Or is there some other reason?
I was simply trying to make the new API as foolproof as I could.

I wasn't proposing that the provider be required to detect thread violations on the Message object. I was proposing that
once the message was sent asynchronously its state changed to something like "unreadable, immutable and unsendable" and
then when the completion listener was invoked its state changed to something like "immutable and unsendable". Messages
sent synchronously would not have any new restrictions imposed.

Again, I think the question is the extent that the spec should attempt to protect the developer against accidentally
misusing the API.

>
> _3. Use of the CompletionListener by the JMS provider (first bullet point)_
> "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. "
> Dust spec have to impose quite such a strict rule? I'm thinking about the case where a MessageProducer is created
> without specifying a destination, and is used to send messages to multiple destinations. In that case, it would seem
> the spec need only mandate that callbacks are performed in the same order /per send destination/ (because that is
> consistent with the ordering for message reception by MessageConsumers - akaik there is no guarantee about the order
> of reception of messages on different destinations).

I think the important item here is "one CompletionListener callback method at a time". This allows the developer to know
that the CompletionListener (for a given session) won't be used concurrently. I think that helps make the API simple to
use.

The statement about message order is intended to make it easier for applications to track the progress of multiple
incomplete sends and I think the need for this is less clear-cut. We don't really know what the completion listener
might be used for in the case where a second message is sent before the first send has completed, and without a clear
need then perhaps we don't need to mandate any message order at all. Does anyone else have any comments on this?

>
> I also noticed couple of minor typos - see inline below.

Thanks,

Nigel
>
> thanks,
> Chris
>
> On 6/27/2012 3:04 AM, 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.*
>>
>> 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.
>>
> Typo: must conf*o*rm to
>>
>> * 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.
>>
> Typo: An application which do*es* not need
>>
>> 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
>>
> See my comments above. I would suggest making the third bullet point consistent with the second.
>> Nigel
>
>