Skip to main content

[jms-spec users] [jsr343-experts] Re: JMS 2.0 PR: Feedback from Goldman Sachs

  • From: Nigel Deakin <nigel.deakin@...>
  • To: jsr343-experts@...
  • Subject: [jms-spec users] [jsr343-experts] Re: JMS 2.0 PR: Feedback from Goldman Sachs
  • Date: Wed, 06 Feb 2013 13:23:11 +0000
  • List-id: <jsr343-experts.jms-spec.java.net>
  • Organization: Oracle Corporation

Here's my reply to these interesting and useful comments from Mike.

(Anyone is welcome to join in and add their own comments.  Mike's team raise a few points on which other views are invited)

On 04/02/2013 11:52, Nigel Deakin wrote:
I received some feedback on the public draft from Mike Marzo.  JCP member representing Goldman Sachs. I've forwarded it here (below) with permission and will reply shortly.

Nigel

Comments on the Public Draft


Clarifications

Load balancing for shared non-durable and durable subscriptions

When a shared subscription has multiple consumers, are there any fairness/load-balancing guarantees around how messages will be distributed to each of these consumers?
No.  JMS doesn't define how messages from a queue are distributed to multiple consumers, and similarly it doesn't define how messages from a shared subscription are distributed to multiple consumers.

Section 4.4.9. "Multiple sessions" explicitly says this for queues, and I think this should be extended to refer to shared subscriptions as well. (Note however that if something is not defined in the spec it is "undefined", irrespective of whether the spec actually says so!)


Semantics of Session.unsubscribe when using shared subscriptions

The specification is not clear on the semantics of Session.unsubscribe when using shared subscriptions.

Consider the case where a shared subscription has consumers in two different clients. When the first client calls Session.unsubscribe, does it result in the subscription being removed for both the clients? Or does Session.unsubscribe take effect only if there are no active message consumers for the subscription?

The javadoc for Session.unsubscribe() says "It is erroneous for a client to delete a durable subscription while there is an active MessageConsumer or TopicSubscriber for the subscription, or while a consumed message is part of a pending transaction or has not been acknowledged in the session." The same sentence is also in the spec (6.11.4).

I think this explicitly answers your question: you can only delete a shared subscription when there are no active consumers.

(The javadoc for JMSContext.unsubscribe() mentions "active consumers". I'll change that to "active (not closed) consumers" and amend Session.unsubscribe() to match).

 
Sending messages asynchronously - commit completion

The specification is explicit about the completion of CompletionListener callbacks for locally transacted sessions, but does not say anything about XA sessions.

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 CompletionListener callbacks have returned before performing the commit or rollback.

Even with XA sessions, commit(on the JTA transaction manager, transaction object) will block till all CompletionListener callbacks have been completed?
When I designed this feature I thought it would be difficult to implement in a JTA transaction. The problem isn't so much the need to wait for CompletionListener callbacks to complete but because the semantics of the commit require it to block until all incomplete sends have been completed, and the commit could be called from any thread.  That's why the spec forbids its use in a Java EE web or EJB container.

I actually started a FAQ of questions like this:
http://java.net/projects/jms-spec/pages/JMS20ReasonsFAQ#Why_is_asynchronous_send_not_permitted_in_a_Java_EE_web_or_EJB_container?


Sending messages asynchronously - callback completion order

Should the specification clarify that there are no guarantees about the order in which the CompletionListener callbacks will be called?

Specifically, if message1 is sent before message2, the callback for message2 can be invoked before the callback for message1?

This is answered in 4.6.2.8. "Use of the CompletionListener by the JMS provider" which states

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.


Suggestions/Enhancements

Context creation using the new API - "Unspecified session mode"

These two methods on JMSContext allow for a context to be created in a "unspecified" sessionMode.
 
JMSContext createContext()
Creates a JMSContext with the default user identity and an unspecified sessionMode.

JMSContext createContext(String userName,String password)
Creates a JMSContext with the specified user identity and an unspecified sessionMode.

What is the semantics of this mode? Can this be tightened up to be one of the valid session modes?

JMSContext has no such methods. The only method on JMSContext which creates a JMSContext takes the session mode as a parameter.

I presume you're referring to the methods on ConnectionFactory. The javadocs describe the semantics:
http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/javax/jms/ConnectionFactory.html#createContext%28%29

The behaviour of the session that is created depends on whether this method is called in a Java SE environment, in the Java EE application client container, or in the Java EE web or EJB container. If this method is called in the Java EE web or EJB container then the behaviour of the session also depends on whether or not there is an active JTA transaction in progress.

In a Java SE environment or in the Java EE application client container:

  • The session will be non-transacted and received messages will be acknowledged automatically using an acknowledgement mode of JMSContext.AUTO_ACKNOWLEDGE For a definition of the meaning of this acknowledgement mode see the link below.

In a Java EE web or EJB container, when there is an active JTA transaction in progress:

  • The session will participate in the JTA transaction and will be committed or rolled back when that transaction is committed or rolled back, not by calling the JMSContext's commit or rollback methods.

In the Java EE web or EJB container, when there is no active JTA transaction in progress:

The session will be non-transacted and received messages will be acknowledged automatically using an acknowledgement mode of JMSContext.AUTO_ACKNOWLEDGE For a definition of the meaning of this acknowledgement mode see the link below
If you think this is unclear please do follow up with further questions.


Context creation in the new API - confusing method calls

The new API offers two different methods to create a context. The subtle difference in the behavior of these two methods might not be obvious to the user. Can the API be changed to make the distinction between these two methods more explicit?

Consider creating two sessions from the same connection. In the new API, the first session (context) is created by

Context firstContext = connectionFactory.createContext("user", "passord",   JMSContext.CLIENT_ACKNOWLE

To create the second session (context) using the same connection, one has to use a different method call; the context has to be created using the previously created Context and not the ConnectionFactory

Context secondContext = firstContext.createContext(JMSContext.CLIENT_ACKNOWLEDGE)

Using the first method call results in the creation of a new connection and a new session. The old API, by virtue of having separate Connection and  Session classes, made this distinction obvious to the user of the API.

11.1. "Goals of the simplified API" lists the goals of the simplified API. One of these was "To reduce the number of objects needed to send and receive messages, and in particular to combine the JMS Connection, Session and MessageProducer objects into a single object."

This was considered particularly appropriate for Java EE web or EJB applications, given that in such applications you're only allowed to create one session per connection anyway.

However for Java SE applications (and the Java EE application client container) we need to allow multiple JMSContext objects to share the same connection. I initially suggested having a method on ConnectionFactory which took an existing JMSContext as a parameter, but someone suggested moving the method to the JMSContext itself, and I agreed that this was simpler.


Setting a CompletionListener on a JMSMessageProducer - Asymmetric API

The method to set a CompletionListener on a JMSMessageProducer is different than that for a MessageProducer. Can both the methods be made symmetric?

When using a MessageProducer, the asynchronous send callback has to be set on per send basis

send(Destination destination, Message message, CompletionListener completionListener)

But when using a JMSMessageProducer, the callback can be set once on the producer

setAsync(CompletionListener completionListener)

Given that old and new APIs are intended to be "parallel"/"equivalent" APIs, it might help to make the method calls as symmetric as possible.

The two APIs are intended to offer the same messaging functionality, but they are not intended to offer the same API style. The whole point of the simplified API was to offer a better style.

The JMSProducer API is designed to avoid an explosion in send methods by allowing each option to be specified using a separate method. Essentially the JMSProducer is a temporary, throwaway object which simply holds parameters for the subsequent send (builder pattern).

context.createProducer().
   setProperty("foo", "bar").
   setTimeToLive(10000).
   setDeliveryMode(NON_PERSISTENT).
   setDisableMessageTimestamp(true).
   send(inboundQueue, body);


MessageProducer has a different style, with all the send options being specified as parameters on the send method:

    send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive)

I think the JMSProducer style is much more flexible. 

Allowing completion listener to be specified as a parameter on the MessageProducer send method was an attempt to confirm with the  existing API style of MessageProducer. This does have a drawback of requiring many send methods.

We could have certainly done that differently, with a method MessageProducer.setAsync, though that would be less consistent with the other methods on Session. Would you prefer that? Would anyone else like to comment?


In this case, both JMSMessageProducer and MessageProducer can allow setting a CompletionListener during creation and during send.



Delivery Delay - Relationship to JMSExpiration

The specification does not describe the behavior when the message delivery delay and the expiration are contradictory.

Hmm. I would have thought that the required behaviour was fairly obvious: if the time to live is less than the delivery time then the message would expire before it was delivered.  Does anyone else think this is unclear?

Note that even if the time to live was greater than the delivery time, if there are no consumers on the destination (or they are very slow) then the message would expire before it was delivered. Setting delivery delay does not override message expiration.


Specifically, the send method should throw an exception, if the message's delivery delay is greater than the message's expiration (time to live). (i.e JMSDeliveryTime cannot be greater than JMSExpiration).
 
I think an exception is most appropriate when the JMS provider simply doesn't know what to do with the information provided. For example a negative time to live is meaningless, and so a provider would be at liberty to reject this as invalid. However I'm not sure that this is the case when the time to live is less than the delivery delay, since by expiring the message at the time specified the JMS provider would be doing exactly what it was asked to do.


Delivery Delay - Unresolved issue

From the specification

There is an unresolved issue regarding the delivery of messages to topics which have a delivery delay specified. This is whether the decision to add a message to a subscription (whether durable or non-durable) should be made (a) when the message reaches its delivery time or (b) when the message is sent.


We agree that this is an edge case. But we would prefer option (a) as it closely mirrors the publisher's intent. i.e If a publisher intends for a message to be available for consumption 30 minutes from now, consumers who are currently not connected but who connect to the broker 30 minutes from now should be able to receive the message.

Thank you for your comment.

The spec goes on to say
If (a) were adopted it would require the JMS provider to keep all messages in the server until their delivery time is reached, even if there were no durable or non-durable subscriptions in existence. This might even be needed for non-persistent messages. Adopting (b) does not require this and by not requiring a message to be held separately from a subscription is closer to the way in which JMS providers work now. Forcing a JMS provider to implement (a) might potentially add a significant burden simply to cater for an unimportant edge case.

In this specification option (b) has been chosen, and section 4.12 "Delivery delay" states that if a message is published to a topic, it will only be added to a durable or non-durable subscription on that topic if the subscription exists at the time the message is sent and continues to exist at the time the specified message delivery time is reached.
Since then I raised this with the expert group and proposed that the reasons for (b) still stand and we should confirm that option
http://java.net/projects/jms-spec/lists/jsr343-experts/archive/2013-01/message/30
There weren't strong views, and although one or two people suggested deliberately leaving this undefined, no-one was explicitly opposed to (b), so that's where thing stand currently.

More views on this would be welcome.


Disallow white space in subscription names

JMS 1.1 did not define what characters were valid in a durable subscription name but JMS 2.0 defines a minimum set of characters that must be valid in a durable or non-durable subscription name and supported across all providers.

Whitespace is not in the list of valid identifiers but being a white list, it might still be allowed by JMS providers. Single/multiple leading/trailing white spaces in durable names cause operational problems which are difficult to diagnose and troubleshoot. e.g Accidental addition of a trailing white space results in a completely new durable being created.

Can white space be disallowed in subscription names?

Java EE compatibility rules mean we can't introduce restrictions that would break existing applications, so all we can do is to define what characters a JMS provider must support, not those that they can't.

http://java.net/projects/javaee-spec/pages/CompatibilityRequirements


JMSXDeliveryCount - Clarify prefetch behavior

Some JMS providers, increment the delivery count on message prefetch. e.g A message which has been prefetched (by the client library) 5 times will have a JMSXDeliveryCount of 5 even though the message was actually delivered to the client (from a receive call) only once. This results in incorrect poison message handling.

3.5.11. "JMSXDeliveryCount" says "When a client receives a message the mandatory JMS-defined message property JMSXDeliveryCount will be set to the number of times the message has been delivered. The first time a message is received it will be set to 1, so a value of 2 or more means the message has been redelivered."

This is pretty clear that "The first time a message is received it will be set to 1".

Whilst JMSXDeliveryCount, like JMSRedelivered, may sometimes give false positives (e.g. after a consumer failure, due to a provider not knowing whether a message was delivered or not) both values are related to deliveries to the client application, not the movement of messages from one part of the JMS provider to another.

Which JMS provider(s) have the behaviour you mention? Most of the major providers are represented on this expert group...

Can the specification be explicit the JMSXDeliveryCount should be incremented only if the message has been returned from a receive call?


Hmm. The specification uses the word "delivered" in hundreds of places, including in the spec for JMSRedelivered. In all cases the word "delivered" means delivered to the client application, not delivered from one part of the JMS provider to another.

I didn't think that needs to be spelled out...but if existing vendors have a different interpretation then perhaps we should.


Security- Kerberos authentication

Can JMS standardize on an authentication scheme like Kerberos? (SASL with Kerberos will be more flexible).

We realize that this might not be possible for JMS 2.0, but will be good feature to have in future versions.

Can you please log this as an issue at http://java.net/jira/browse/JMS_SPEC
What would this actually mean in terms of the JMS API? Please be as specific as possible.


Typos

Non-durable subscriptions

Refer: JMS_SPEC-40, Section 6.11, Pg 69. The last paragraph (bullet point) should read

A shared durable subscription is identified by name and an

instead of

A shared non-durable subscription is identified by name and an

Delivery Delay

Refer: Section B.5.8, Pg 163. The second paragraph of section B.5.8 should read

A new section 4.12 "Delivery delay" and a corresponding new section

instead of

A new section 4.13 "Delivery delay" and a corresponding new section

 
Thanks for these!

Nigel

 

 



[jms-spec users] [jsr343-experts] JMS 2.0 PR: Feedback from Goldman Sachs

Nigel Deakin 02/04/2013

[jms-spec users] [jsr343-experts] Re: JMS 2.0 PR: Feedback from Goldman Sachs

Nigel Deakin 02/06/2013
 
 
Close
loading
Please Confirm
Close