<< Back to previous view

[JMS_SPEC-40] Allow multiple consumers to be created on the same topic subscription Created: 05/Aug/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on JMS_SPEC-93 Does changing the noLocal flag when c... Resolved
blocks MQ-178 Implement new API to allow multiple c... Closed
blocks MQ-175 support optional clientId when creati... Closed
blocks MQ-229 Implementing noLocal behavior for sha... Closed
Duplicate
is duplicated by JMS_SPEC-23 Allow and specify clustered durable s... Closed
Tags: pd20-added
Participants: chris.barrow, clebertsuconic and Nigel Deakin

 Description   

This proposal would allow multiple message consumers to be used to consume messages from the same durable or non-durable topic subscription. This would increase scalability by allowing messages from a topic to be processed by multiple consumers in a Java SE environment. Note that the existing JMS 1.1 API already allows this to be achieved for messages from a queue.

The multiple consumers might be in the same or different JVMs. Within the same JVM, the multiple consumers might use the same or different sessions and connection. Note, however, that the normal restrictions on the use of a session by multiple threads would continue to apply.

Durable subscriptions

For durable subscriptions, there would be no need to change the existing API. Applications would simply be allowed to create multiple consumers on the same durable subscription:

This affects the following JMS existing JMS 2.1 methods on Session (and its subtypes QueueSession, TopicSession, XASession, XAQueueSession and XATopicSession):

createDurableSubscriber(Topic topic, String name)
createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) 

It also affects the following JMS new JMS 2.0 methods on Session (and its subtypes QueueSession, TopicSession, XASession, XAQueueSession and XATopicSession) (added in JIRA issue 51 ):

createDurableConsumer(Topic topic, String name)
createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

And in the new JMS 2.0 simplified API, it also affects the following method on JMSContext:

createDurableConsumer(Topic topic, String name)
createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

All these methods currently have a restriction "Only one session at a time can have a TopicSubscriber for a particular durable subscription.". This restriction would be removed.

No change is proposed to the existing JMS requirement that only one connection may have a given clientID. This is defined in JMS 1.1 Section 4.4.3.2 "Client identifier", which states:

By definition, the client state identified by a client identifier can be 'in use' by only one client at a time. A JMS provider must prevent concurrently executing clients from using it.

This means that if a durable subscription is created by a connection with clientId set then it will not be possible to create a second consumer on it using a different connection.

However in JMS 2.0, clientId will become optional when creating a durable subscription (see JIRA issue 39). If a durable subscription is created by a connection with clientId unset then other connections may freely create further consumers on the same durable subscription.

This means that for two message consumers on different connections to share a durable subscription, clientId would need to be left unset.

In addition, the effect of using a different topic or message selector than was used when the subscription was first created needs to be amended. Currently this states (from the javadoc for Session.createDurableSubscriber):

A client can change an existing durable subscription by creating a durable TopicSubscriber with the same name and a new topic and/or message selector. Changing a durable subscriber is equivalent to unsubscribing (deleting) the old one and creating a new one.

This behaviour will continue, but only if there are no other active consumers on the durable subscription. If there is an active consumer on the durable subscription, and an attempt is made to create an additional consumer with a different topic or message selector, then a JMSException will be thrown (in the case of JMSContext a JMSRuntimeException will be thrown).

The semantics for the unsubscribe methods on Session and JMSContext would remain unchanged. The javadocs state that "It is erroneous for a client to delete a durable subscription while there is an active MessageConsumer or TopicSubscriber for the subscription". This will continue to be the case.

Non-durable subscriptions

For non-durable subscriptions, the JMS 1.1 specification specifies that if two non-durable TopicSubscribers are created on the same topic then two independent subscriptions are created: a copy of each message is sent to every consumer on that topic (with an appropriate message selector).

To allow two consumers to share the same subscription, so that they can share the load of processing messages from that subscription, then new API is required. To allow the consumers to specify that they wish to use the same non-durable subscription, they will need to specify the same sharedSubscriptionName.

The following new methods on Session (and its subtypes) are proposed:

MessageConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName);
MessageConsumer createSharedConsumer(
   Destination destination, String sharedSubscriptionName, String messageSelector)
MessageConsumer createSharedConsumer(
   Destination destination, String sharedSubscriptionName, String messageSelector, boolean NoLocal)

Note that if these methods were called simply createConsumer there would be a clash with the existing method createConsumer(Destination destination, String messageSelector). Note that these methods take a Topic, not a Destination.

In the new simplified API, the following new methods on JMSContext are proposed:

JMSConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName)
JMSConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName, String messageSelector)
JMSConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName, String messageSelector, boolean noLocal)

Note that a given shared subscription does not exist if there are no consumers using it.



 Comments   
Comment by Nigel Deakin [ 19/Aug/11 03:12 PM ]

It should be noted that the JMS 1.1 specification currently states that this feature is not currently available.

4.4.15 Concurrent Message Delivery

...

Note that JMS itself does not provide the facilities for concurrently processing a topic’s message set (the messages delivered to a single consumer). A client could use a single consumer and implement all the multithreading logic needed to concurrently process the messages; however, it is not possible to do
this reliably, because JMS does not have the transaction facilities needed to handle the concurrent transactions this would require.

Comment by Nigel Deakin [ 30/Mar/12 11:52 AM ]

Description completely updated.

Comment by Nigel Deakin [ 30/Mar/12 11:54 AM ]

Added a dependency on JMS_SPEC-93, which concerns the effect of changing noLocal when activating a durable subscription.

Comment by Nigel Deakin [ 10/Apr/12 03:16 PM ]

Added clarification that the semantics of the unsubscribe methods on Session and JMSContext would remain unchanged.

Comment by Nigel Deakin [ 13/Apr/12 02:30 PM ]

Javadoc and spec updates (for durable subscriptions)

I've now updated the javadocs and the draft spec to incorporate these changes.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

Changes to Javadocs

I've made the following changes to the javadoc for all the following methods on Session:

  • TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException;
  • TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException;
  • MessageConsumer createDurableConsumer(Topic topic, String name) throws JMSException;
  • MessageConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException;

and for the following methods on JMSContext:

  • JMSConsumer createDurableConsumer(Topic topic, String name);
  • JMSConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal);

I've deleted

Only one session at a time can have a consumer for a particular durable subscription.

and replaced it with:

A durable subscription may have more than one active consumer (this was not permitted prior to JMS 2.0). Each message from the subscription will be delivered to only one of the consumers on that subscription.

I've deleted

A client can change an existing durable subscription by calling [this method] with the same name and client identifier (if used), and a new topic and/or message selector. Changing a durable subscription is equivalent to unsubscribing (deleting) the old one and creating a new one.

and replaced it with:

If there are no active consumers on the durable subscription (and no consumed messages from that subscription are still part of a pending transaction or are not yet acknowledged in the session), and this method is used to create a new consumer on that durable subscription, specifying the same name and client identifier (if set) but a different topic or message selector, then the durable subscription will be deleted and a new one created. However if there is an active consumer on the durable subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name and client identifier (if set) but a different topic or message selector, then a JMSException will be thrown.

Changes to spec

Section 6.11.1 "Durable subscriptions", which contains similar text to the javadoc comments of the above methods, has been similarly changed:

I've deleted

Only one session at a time can have a consumer for a particular durable subscription.

and replaced it with:

A durable subscription may have more than one active consumer (this was not permitted prior to JMS 2.0). Each message from the subscription will be delivered to only one of the consumers on that subscription.

I've deleted

A client can change an existing durable subscription by calling [this method] with the same name and client identifier (if used), and a new topic and/or message selector. Changing a durable subscription is equivalent to unsubscribing (deleting) the old one and creating a new one.

and replaced it with:

If there are no active consumers on the durable subscription (and no consumed messages from that subscription are still part of a pending transaction or are not yet acknowledged in the session), and this method is used to create a new consumer on that durable subscription, specifying the same name and client identifier (if set) but a different topic or message selector, then the durable subscription will be deleted and a new one created. However if there is an active consumer on the durable subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name and client identifier (if set) but a different topic or message selector, then a JMSException will be thrown.

A new section has been added to Appendix B "Change history" to describe this change.

Comment by Nigel Deakin [ 17/Apr/12 11:17 AM ]

Javadoc and spec updates (for non-durable subscriptions)

I've now updated the javadocs and the draft spec to incorporate these changes.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

Changes to Javadocs

I've added the following new methods on Session

  • MessageConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName) throws JMSException;
  • MessageConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector) throws JMSException;
  • MessageConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal) throws JMSException;

and the following new methods on JMSContext

  • JMSConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName);
  • JMSConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector);
  • JMSConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal);

Here's an example of the javadoc for one of the methods on Session:

	/**
	 * Creates a shared non-durable subscription with the specified name on the
	 * specified topic, and creates a <code>MessageConsumer</code> on that
	 * subscription, specifying a message selector and whether messages
	 * published by its own connection should be added to the subscription.
	 * <p>
	 * If a shared non-durable subscription already exists with the same name
	 * and the same topic and message selector then this method creates a
	 * <code>MessageConsumer</code> on the existing subscription.
	 * <p>
	 * A non-durable shared subscription is used by a client which needs to be
	 * able to share the work of receiving messages from a topic subscription
	 * amongst multiple consumers. A non-durable shared subscription may
	 * therefore have more than one consumer. Each message from the subscription
	 * will be delivered to only one of the consumers on that subscription. Such
	 * a subscription is not persisted and will be deleted (together with any 
	 * undelivered messages associated with it) when there are no consumers on it.
	 * <p>
	 * A consumer may be created on a non-durable shared subscription using the
	 * <code>createSharedConsumer</code> methods on <code>JMSContext</code>,
	 * <code>Session</code> or <code>TopicSession</code>.
	 * <p>
	 * If there is an active consumer on the non-durable shared subscription (or
	 * a consumed message from that subscription is still part of a pending
	 * transaction or is not yet acknowledged in the session), and an attempt is
	 * made to create an additional consumer, specifying the same name but a
	 * different topic or message selector, then a <code>JMSException</code>
	 * will be thrown.
	 * <p>
	 * The <code>noLocal</code> argument is for use when the session's connection is also
	 * being used to publish messages to the topic. If noLocal is set to true
	 * then messages published to the topic by its own connection will not be
	 * added to the non-durable shared subscription. The default value of this
	 * argument is false.
	 * <p>
	 * There is no restriction to prevent a shared non-durable subscription and
	 * a durable subscription having the same name. Such subscriptions would be
	 * completely separate.
	 * 
	 * @param topic
	 *            the <code>Topic</code> to subscribe to
	 * @param sharedSubscriptionName
	 *            the name used to identify the shared non-durable subscription
	 * @param messageSelector
	 *            only messages with properties matching the message selector
	 *            expression are added to the non-durable subscription. A value
	 *            of null or an empty string indicates that there is no message
	 *            selector for the non-durable subscription.
	 * @param noLocal
	 *            if true, messages published by its own connection will not be
	 *            added to the non-durable subscription.
	 * 
	 * @throws JMSException
	 *             if the session fails to create the non-durable subscription
	 *             and <code>MessageConsumer</code> due to some internal error.
	 * @throws InvalidDestinationException
	 *             if an invalid topic is specified.
	 * @throws InvalidSelectorException
	 *             if the message selector is invalid.
	 */
	MessageConsumer createSharedConsumer(
           Topic topic, String sharedSubscriptionName, 
           java.lang.String messageSelector, boolean noLocal) 
           throws JMSException;   

Changes to draft spec:

The existing section 6.11 "TopicSubscriber" has been extended to cover shared non-durable subscriptions:

Updated introductory section 6.11 "TopicSubscriber":

A client consumes messages from a topic by creating a subscription on that topic, and creating a MessageConsumer or TopicSubscriber on that subscription.

In general, a subscription will receive a copy of every message sent to the topic. However if a message selector is specified then only those messages whose properties match the message selector will be added to the subscription.

In addition, if the noLocal flag was specified when a MessageConsumer or {{TopicSubscriber}}was created, then any messages sent using the same connection will not be added to the subscription.

Each copy of the message is treated as a completely separate message. Work done on one copy has no effect on any other; acknowledging one does not acknowledge any other; one message may be delivered immediately, while another waits for its consumer to process messages ahead of it.

Subscriptions may be durable or non-durable.

A non-durable subscription exists only so long as a MessageConsumer or TopicSubscriber object exists to consume messages from it. A non-durable subscription may be either unshared or shared.

An unshared non-durable subscription does not have a name and may have only a single MessageConsumer or TopicSubscriber object associated with it. It is created automatically when the MessageConsumer or TopicSubscriber object is created. It is not persisted and is deleted automatically when it is closed. See section 6.11.1 "Unshared non-durable subscriptions" below.

A shared non-durable subscription is identified by name, which may be used to associate several MessageConsumer or TopicSubscriber objects with it. It is created automatically when the first MessageConsumer or TopicSubscriber object is created. It is not persisted and is deleted automatically when the last MessageConsumer or TopicSubscriber object is closed. See section 6.11.2 "Shared non-durable subscriptions" below.

A durable subscription is identified by a name and an optional client identifier, which may be used to associate several MessageConsumer or TopicSubscriber objects with it. A durable subscription is created automatically when the first MessageConsumer or TopicSubscriber object is created. It is persisted and continues to exist until explicitly deleted, even if there are no MessageConsumer or TopicSubscriber objects consuming messages from it. See section 6.11.3 "Durable subscriptions" below.

New section 6.11.1. "Unshared non-durable subscriptions":

An unshared non-durable subscription is the simplest way to consume messages from a topic.

An unshared non-durable subscription is created, and a MessageConsumer created on that subscription, using one of the createConsumer methods on Session, JMSContext or TopicSession.

Alternatively an unshared non-durable subscription is created, and a TopicSubscription created on that subscription, using one of the createSubscriber methods on TopicSession.

An unshared non-durable subscription does not have a name. Each call to createConsumer or createSubscriber creates a new subscription.

An unshared non-durable subscription only exists for as long as the MessageConsumer or TopicSubscriber exists. This means that any messages sent to the topic will only be added to the subscription whilst the MessageConsumer or TopicSubscriber is active. The subscription is not persisted and will be deleted (together with any undelivered messages associated with it) when the consumer is closed.

If a message selector is specified then only messages with properties matching the message selector expression will be added to the subscription.

The noLocal argument may be used to specify that messages published to the topic by its own connection must not be added to the subscription.

Each unshared non-durable subscription has a single consumer. If the application needs to create multiple consumers on the same subscription then a shared non-durable subscription should be used instead. See section 6.11.2 "Shared non-durable subscriptions".

If the application needs to be able to receive messages that were sent to the topic even when there was no active consumer on it then a durable subscription should be used instead. See section 6.11.3 "Durable subscriptions".

New section 6.11.2. "Shared non-durable subscriptions":

A non-durable shared subscription is used by a client which needs to be able to share the work of receiving messages from a topic subscription amongst multiple consumers. A non-durable shared subscription may therefore have more than one consumer. Each message from the subscription will be delivered to only one of the consumers on that subscription.

A shared non-durable subscription is created, and a MessageConsumer created on that subscription, using one of the {[createSharedConsumer}} methods on Session, JMSContext or TopicSession. The same methods may be used to create a MessageConsumer on an existing shared non-durable subscription.

A shared non-durable subscription is identified by a name specified by the client.

A shared non-durable subscription only exists for as long as a MessageConsumer or TopicSubscriber exists on the subscription. This means that any messages sent to the topic will only be added to the subscription whilst a MessageConsumer or TopicSubscriber is active. The subscription is not persisted and will be deleted (together with any undelivered messages associated with it) when the last consumer on the subscription is closed.

If a message selector is specified then only messages with properties matching the message selector expression will be added to the subscription.

The noLocal argument may be used to specify that messages published to the topic by its own connection must not be added to the subscription.

If there is an active consumer on the non-durable shared subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name but a different topic or message selector, then a JMSException will be thrown.

There is no restriction to prevent a shared non-durable subscription and a durable subscription having the same name. Such subscriptions would be completely separate.

Comment by Nigel Deakin [ 13/Sep/12 05:26 PM ]

What does the noLocal mean when the subscription is shared? This question applies to both durable and non-durable subscriptions.

In very broad terms noLocal is a way of designating that if a connection creates a consumer on a subscription, then messages sent by that connection will not be added to the subscription.

For JMS 1.1 non-durable subscriptions this is easy to define, since you can only have one consumer on a subscription, and the moment its connection is closed, the subscription will be deleted.

For JMS 1.1 durable subscriptions this is slightly harder to define, since the connection that created the durable subscription could close and "come back later" to reactivate the same durable subscription. In that case, we define that any messages sent by a connection with the same client identifier as the connection which created the subscription will not be added to the subscription.

In JMS 2.0 we introduce three new features to topic subscriptions:

  • We allow a durable subscription to have multiple consumers (see this issue)
  • We allow the creation of named non-durable subscriptions which may have multiple consumers (see this issue)
  • We allow client identifier to be unset when creating a durable subscription (see JMS_SPEC-39)

What does this mean for noLocal? We need to consider the following cases:

1. Unshared durable subscription with client identifier set
2. Unshared durable subscription with client identifier unset
3. Shared durable subscription with client identifier set
4. Shared durable subscription with client identifier unset
5. Shared non-durable subscription with client identifier set
6. Shared durable non-subscription with client identifier unset

1. Unshared durable subscription with client identifier set

This case is already allowed in JMS 1.1 and the meaning of noLocal has been clarified in JMS_SPEC-65.

Any messages published to the topic using the connection that created the durable subscription, or any other connection with the same client identifier, will not be added to the durable subscription.

2. Unshared durable subscription with client identifier unset

This case is new in JMS 2.0 and the meaning of noLocal has already been defined in JMS_SPEC-65: this will not be allowed and will throw an exception.

3. Shared durable subscription with client identifier set

This case is new in JMS 2.0. Since two connections cannot have the same client identifier all consumers on the durable subscription must use the same connection. We can simply apply the rule given in (1).

Any messages published to the topic using the connection that created the durable subscription, or any other connection with the same client identifier, will not be added to the durable subscription.

4. Shared durable subscription with client identifier unset

This case is new in JMS 2.0. We can simply apply the rule given in (2) and not allow this.

5. Shared non-durable subscription with client identifier set

This case is new in JMS 2.0 and we don't have a rule yet which covers it.

We could simply apply the same rule as for durable subscriptions, given in (1) above. However it should be noted that unlike for durable subscriptions, the client identifier will not be part of the subscription name and so we may have multiple consumers with different client identifier. In that case why should we assign a special status to the client identifier that originally created the subscription?

An alternative is to adopt a rule based not on client identifier but on whether the connection has created a consumer on the subscription. In that case, once a connection has created a consumer on the subscription its messages would no longer be added to the subscription. This would then give equal status to all consumers. However it would be inconsistent with durable subscriptions.

6. Shared durable non-subscription with client identifier unset

If we adopted the same rule as for durable subscriptions we would simply not allow this. However if we adopted the alternative given in (5) above we could also apply it in this case.

Summary

For shared non-durable subscriptions we have two alternatives:

A. Adopt a rule similar to that for durable subscriptions, based on client id

If noLocal is set to true, and the client identifier is set, then any messages published to the topic using the connection that created the durable subscription, or any other connection with the same client identifier, will not be added to the durable subscription.

If the client identifier is unset then setting noLocal to true will cause a IllegalStateException to be thrown.

B. Adopt a rule based on whether a connection has created a consumer on the shared subscription

Any messages published by a connection which has created a consumer on the shared non-durable subscription will not be added to the subscription.

Comment by chris.barrow [ 13/Sep/12 07:13 PM ]

I would strongly urge against clientID having any bearing on non-durables.
I would vote for the alternative in 5 (i.e. B), except there is one little wrinkle that needs to be addressed: the part highlighted in the copy below:

An alternative is to adopt a rule based not on client identifier but on whether the connection has created a consumer on the subscription. In that case, once a connection has created a consumer on the subscription its messages would no longer be added to the subscription. This would then give equal status to all consumers. However it would be inconsistent with durable subscriptions.

Does the highlighted part means that if I send messages on the connection then shared consumers on the same subscription on the same or different connections would not receive them? I think that is the desirable behavior. My understanding of the intention of the noLocal parameter is that if you are sending a message then you already know about it (and have dealt with it) so you don't need to receive it. And in this case the receiving "you" should include all of the shared message consumers, since presumably they are cooperating to process the messages.

The only unfortunate thing about this is there is an ambiguity if a shared consumer is created with noLocal=false, then a second is created on the same connection with noLocal=true (or vice versa). Which one "wins"? If the intention is that noLocal=true implies a message sent on the same connection will not be received by any of the sharedConsumers (on the same or different connections), then noLocal=true would have to "win", effectively changing the behavior of the first consumer on-the-fly.

If we consider that the behavior for the above corner case is too unexpected, then there is another option (which we could perhaps call alternative "C"). This would be to apply strictly the same behavior as for createConsumer. That is, when a message is sent on a connection, it would be delivered to any one of the shared consumers on the subscription except ones created on that same connection with noLocal=false. But (as well as being potentially harder to implement) I think this is actually less useful behavior, for the reasons pointed out above (cooperating consumers). So my vote is still for B, provided we clearly define the behavior for this corner case.

BTW, it would be worth pointing out (for any of the options) that the message still gets sent to the destination (topic) even if it doesn't get delivered to the subscription.

Comment by clebertsuconic [ 13/Sep/12 07:20 PM ]

Two things: I may be late on that, but why do we need a createSharedConsumer? If you let specify createDurableSubscription without clientID you are basically creating or reattaching the subscription that already existed. You are just using a global parameter. (i.e. no clientID)

In regard to noLocal, I simply believe we should rule out noLocal & clientID=null, that will make things simpler and clearer. I can't foresee any usecase with clientID=null and noLocal=true anyways. (anything other than that would be an anti-pattern IMO)

Comment by chris.barrow [ 13/Sep/12 09:51 PM ]

There is a fundamental difference between durable and non-durable subscriptions, even in the shared consumer case: durables live for ever (until they are explicitly deleted) and they store messages even when there are no active consumers (rather like queues). Non-durables only survive as long as there is at least one active consumer, so there is no persistent message store.

Since clientID has no impact on the identity of a non-durable subscription, I strongly think it should have no influence on their behavior. The issue I pointed out above when two shared non-durable consumers are created on the same connection with different noLocal values would still remain even if we do insist that clientID be set for noLocal=true.

I guess you are worried about the inconsistency between the durable and non-durable cases. I do think you have a point there. Maybe we should reconsider the durable noLocal behavior to make it agnostic about clientID as well? The rule suggested for nondurables ("once a connection has created a consumer on the subscription its messages would no longer be added to the subscription.a") could perfectly well be applied to durables as well. There's no good reason I can see why the noLocal behavior should outlive the consumer (and the connection) in the durables case. After all, it is the subscription that is durable, not the consumer. And it is the consumer that has noLocal=true, not the subscription.

Comment by Nigel Deakin [ 17/Sep/12 04:05 PM ]

To answer Clebert: createSharedConsumer is for non-durable subscriptions. We need a new method because the existing createConsumer method doesn't have a subscriptionName parameter.

For durable subscriptions, I have accepted your suggestion that if the client identifier is not set and noLocal is true then an IllegalStateException should be thrown.

Comment by Nigel Deakin [ 17/Sep/12 04:48 PM ]

To Answer Chris's comment of 13/Sep/12 07:13 PM:

1. My option B was that if noLocal was true then once a connection has created a consumer on the subscription its messages would no longer be added to the subscription. This means they would not be delivered to any consumers. I think that was what you were asking for. As you say, if you have multiple consumers on the same subscription they are cooperating to process the messages so they should behave the same way.

2. You ask what would happen if "a shared consumer is created with noLocal=false, then a second is created on the same connection with noLocal=true (or vice versa). Which one wins?"

If the first session still had a consumer on the shared non-durable subscription, then if a second connection or session tried to create a consumer on the same subscription with a different topic, message selector or noLocal value then they are trying to change the nature of the subscription, so it should throw an exception.

Obviously if the first connection was closed before the second connection created the consumer then this would not be a problem, as the subscription would have been deleted when the first consumer was closed.

3. Your option (C) shouldn't then be needed

4. You suggest "it would be worth pointing out (for any of the options) that the message still gets sent to the destination (topic) even if it doesn't get delivered to the subscription."

Yes, definitely. More accurately, even if a message doesn't get added to one particular subscription on the topic, it will still be added to all other elegible subscriptions on the same topic.

To answer Chris's comment of 13/Sep/12 09:51 PM:

5. You write "There's no good reason I can see why the noLocal behavior should outlive the consumer (and the connection) in the durables case. After all, it is the subscription that is durable, not the consumer. And it is the consumer that has noLocal=true, not the subscription."

That's quite an important point. However one could argue that the noLocal flag is really just another kind of message selector on the subscription (based on the client id that sent the message), and so continues to exist irrespective of whether there were any consumers active.

However I think we ultimately have a slightly arbitrary decision here. noLocal is a distinctly obscure feature: it would be interested to know how much it gets used.

We should also consider an option D, which is when the new createSharedConsumer method is used to create a shared non-durable subscription (which is a new feature of JMS 2.0), there is no noLocal option at all.

Comment by Nigel Deakin [ 05/Nov/12 07:27 PM ]

Because shared non-durable subscriptions are so similar in concept to durable subscriptions I think we should aim to make the definition of noLocal for the two types of subscription as similar as possible. This means:

1. Changing the definition of a shared non-durable subscription so that the client identifier, if set, forms part of the name of the shared non-durable subscription (as is already the case with durable subscriptions).

2. Defining noLocal in exactly the same way for shared non-durable subscriptions as for durable subscriptions:

When a durable or shared non-durable subscription is created on a topic, the noLocal argument may be used to specify that messages published to the topic by its own connection or any other with the same client identifier will not be added to the durable subscription. If the client identifier is unset then setting noLocal to true will cause an exception to be thrown.

Since only one connection may have a given client identifier at a time, this means that the noLocal flag may only be used when there is a single connection consuming from a subscription. I believe this is a benefit as it it gives us a clear, simple definition, it maintains consistency with JMS 1.1, and avoiding the need to contrive complex and entirely hypothetical use cases in which noLocal is used in conjunction with multiple consumers.

Following consultation with the expert group and user alias I have now added this definition to the draft specification.

To see the new text in the spec, please download the latest draft here (log in to java.net first) and read section 6.11.2. "Shared non-durable subscriptions"

You can find the updated API documentation for Session.createSharedConsumer here and for JMSContext.createSharedConsumer here

I have added a special note to section A.3. "Unresolved issues in the JMS 2.0 Public Draft" to state that this is an issue which we aren't completely sure about, and that when this specification goes to public review we're particularly welcome comments on it.

Comment by Nigel Deakin [ 14/Nov/12 02:51 PM ]

Reopening this issue as this feature changes the behaviour of Session.createDurableSubscription in an incompatible way

Incompatibility 1.

According to JMS 1.1 section 6.11.1: "Only one session at a time can have a TopicSubscriber for a particular durable subscription.". The spec and API docs do not explicitly state that an attempt to create two {{TopicSubscriber}}s on the same durable subscription should throw an exception, but I think this is implied, at least for the case where different sessions are used.

In JMS 2.0 we are proposing to remove this restriction and allow multiple {{TopicSubscriber}}s(and {{MessageConsumer}}s) to be created on the same durable subscription.

Incompatibility 2.

According to JMS 1.1 section 6.11.1: "Sessions with durable subscribers must always provide the same client
identifier." The spec and API docs do not explicitly state that clientId must be set when calling createDurableSubscription, and that an exception must be thrown if it is not set, but again I think this is is implied.

In JMS 2.0 we are proposing to remove this restriction and allow clientId to be either set or unset when Session.createDurableSubscription is called. If clientId is set then the combination of clientId and subscription name will be used to identify the durable subscription. If clientId is not set then the subscription name will be used to identify the durable subscription.

Comment by Nigel Deakin [ 21/Nov/12 05:17 PM ]

I have updated the API for creating durable subscriptions to retain backwards compatibility with JMS 1.1 as follows:

The following methods have been reverted to the JMS 1.1 behaviour:

Methods on Session:

  • TopicSubscriber createDurableSubscriber(Topic topic, String name) (JMS 1.1)
  • TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) (JMS 1.1)
  • MessageConsumer createDurableConsumer(Topic topic, String name) (JMS 2.0)
  • MessageConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal) (JMS 2.0)

Methods on JMSContext:

  • JMSConsumer createDurableConsumer(Topic topic, String name)
  • JMSConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

These methods:

  • Will only allow a single consumer on a durable subscription
  • clientId MUST be set

I have also added the following new methods to support shared durable subscriptions:

Methods on Session:

  • MessageConsumer createSharedDurableConsumer(Topic topic, String name)
  • MessageConsumer createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

Methods on JMSContext:

  • JMSConsumer createSharedDurableConsumer(Topic topic, String name)
  • JMSConsumer createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

These methods:

  • Will allow multiple consumers on a durable subscription
  • clientId may or may not be set

You can see the updated API docs here:
http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/index.html

I have also updated the spec to incorporate these changes:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

Comment by Nigel Deakin [ 12/Feb/13 05:24 PM ]

The JMS 2.0 expert group has agreed that the noLocal parameter serves no useful purpose for shared subscriptions (both durable and non-durable) and should be removed.

Changes to Session:

Removed:

  • createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal)

Changed:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

To:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector)

Changes to JMSContext

Removed:

  • createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal)

Changed:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

To:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector)
Generated at Fri Apr 18 05:01:50 UTC 2014 using JIRA 4.0.2#472.