users@jms-spec.java.net

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

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Mon, 17 Sep 2012 20:06:01 +0100

The RI team continues to be busy implementing the new features of JMS 2.0 and has reported the need for clarifications
of the new asynchronous send feature. I would therefore like to propose a number of clarifications below. I think these
are generally minor.

*** 1. Clarify that if onException is called, the message may not have been successfully sent.

I think this is generally already implied, but I propose to clarify this by changing the javadoc for onException to
state that it "Notifies user that the specified exception was thrown. If an exception occurs it is undefined whether or
not the message was successfully sent".

*** 2. Clarify the behaviour when session.commit() consumer.close() is called when there are still incomplete async send
operations outstanding.

This is currently defined in section 4.6.2.3 "Close, commit or rollback" as follows (with similar text in the API docs):

"If the session is transacted (uses a local transaction) then when the commit or rollback method 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 the close method 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."

I have been asked whether it would be permissible for the provider to impose a timeout and call onException for all
incomplete sends which would allow the commit, rollback or close to return without any delay.

My response is that the intention here is for the commit, rollback or close to wait for all incomplete sends to be
completed (i.e. acknowledged). Applications should be able to expect that in normal operation, calling commit, rollback
or close will allow all incomplete sends to complete and onCompletion to be called for each one. If the JMS provider
decides that the JMS server has become unresponsive, perhaps using a timeout, then it might call onException for all
outstanding sends, but it shouldn't call onException simply because the application has called commit, rollback or close.

However this is an area where I don't think the spec should be too prescriptive. So I propose to simply add a sentence

"Incomplete sends should be allowed to complete normally unless an error occurs "

*** 3. Clarify what happens if you call commit, rollback or close from a callback method? Won't this deadlock?

Yes, this is a good point. Since these methods are required to wait until all incomplete sends are complete and all
callbacks have returned, then calling them from a callback method will cause deadlock.

This is similar to calling stop or close from a message listener, which we clarified in JMS_SPEC-48.

I propose that the spec simply state that commit, rollback or close may not be called from a callback method and must
throw a javax.jms.IllegalStateException for the methods on Connection and Session and
javax.jms.IllegalStateRuntimeException for the methods on JMSContext.

*** 4. In a local transaction, if an aSync send fails, and either send() throws an exception or onException is called,
then can the transaction can be committed?

In a local transaction, and a call to the normal synchronous send() throws an exception, then the application can catch
the exception and choose whether to commit or rollback the transaction. If the application calls commit() and the
provider is able to commit all the other work of the transaction then it should do. The provider isn't required to fail
the commit simply because a preceding call to send() threw an exception.

So I would propose the same behaviour for async send. In a local transaction, if an async send fails (either by send()
throwing an exception or by onException being called) then this does not force the subsequent commit to fail.

Note that if the application calls commit when there are incomplete sends, the application needs to be aware that the
transaction may still be committed even if one of these sends fails. If the application needs to be certain that a
particular send has succeeded before calling commit then they should wait for the completion listener to be invoked
before calling commit. (Or they should perform a synchronous send).

I'm not sure whether this needs additional clarification. I don't think the spec explicitly defines this behaviour for
sync sends (unless I have missed it), and no-one has raised it as an issue.

*** 5. The spec states that calls to onCompletion() must take place in the same order as the corresponding call to
send(). Does this also apply to calls to onException()?

That's what the spec currently states. This is intended to make it easier for the application to process any callbacks.
To avoid uncertainty I propose we clarify this by amending 4.6.2.7. "Use of the CompletionListener by the JMS provider"
to state the following:

"A session will only invoke one CompletionListener callback method at a time. For a given MessageProducer or JMSContext,
callbacks (both onCompletion and onException) will be performed in the same order as the corresponding calls to the
asynchronous send method.

"A JMS provider must not invoke the CompletionListener from the thread that is calling the asynchronous send method."

*** 7. Clarification of 4.6.2.1. Quality of service (and corresponding javadoc entries):

This currently states:

"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 CompletionListener. The
CompletionListener must not be invoked earlier than this."

This is a description of the normal, successful case which can be followed by a description of the failure case (see
next point). To clarify that this is the normal, successful case I propose we change this to:

"After the send operation has completed successfully, 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
CompletionListener's onCompletion method. This method must not be called earlier than this."

*** 6. Clarification of the purpose and of CompletionListener onException method

We don't currently say very much about this, so I think this deserves a subsection of its own. So I propose we insert a
new subsection "Exceptions" after 4.6.2.1 as follows:

"If an exception is encountered during the call to the send method then an appropriate exception should be thrown in the
thread that is calling the send method. In this case the JMS provider must not invoke the CompletionListener's
onCompletion or onException method.

"If an exception is encountered which cannot be thrown in the thread that is calling the send method then the JMS
provider must call the CompletionListener's exception method.

"In both cases if an exception occurs it is undefined whether or not the message was successfully sent."


Nigel