users@jms-spec.java.net

[jms-spec users] [jsr343-experts] (JMS_SPEC-73) Define how messages from a topic are delivered to clustered application server instances

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Fri, 15 Jun 2012 16:41:11 +0100

Back in February I logged this JIRA issue on behalf of a member of the community ("Florian"):

http://java.net/jira/browse/JMS_SPEC-73
Define how messages from a topic are delivered to clustered application server instances
(Please see the JIRA issue for Florian's original comments)

When we had a vote on possible new issues a couple of months ago this issue gained four votes: no other issue received
more votes than this.

Background
----------

Separately to this I have been negotiating with the Java EE and EJB spec leads about providing a standard way to
configure JMS MDBs. We discussed this some time ago and agreed on what we wanted to ask the EJB spec to do: the issues are:

http://java.net/jira/browse/JMS_SPEC-54
Define a standard way to configure the destination on which a JMS MDB consumes messages

http://java.net/jira/browse/JMS_SPEC-55
Define a standard way to configure the connection factory used by a JMS MDB to consume messages

http://java.net/jira/browse/JMS_SPEC-30
Define mandatory activation config properties for JMS MDBs

I intend to report back soon to this group with some slightly modified proposals which I hope will be acceptable to the
Java EE and EJB spec leads and their respective EGs.

Subscriptions
-------------

One of the things this EG proposed in JMS_SPEC-30 was that if the user had configured a MDB to use a durable
subscription, but had not specified a durable subscription name, then the Java EE container should generate a suitable
default automatically. This EG proposed that "It is therefore proposed that the EJB specification state that if the
subscription is durable and subscriptionName is not set then the container will automatically set subscriptionName to
the name of the MDB."

I have now been discussing with the the Java EE and EJB spec leads how this might actually been implemented. I expect
the outcome of these discussions will be that the responsibility for setting subscriptionName, if the user has not set
it, should be with the resource adapter rather than the container.

This means that the resource adapter will need to know the name of the MDB, so it can use it to set subscriptionName. To
allow this, the container will need to make the name of the MDB available to the resource adapter. In order that this
name will be unique across multiple application servers it will need to supply a "global MDB name", which uniquely
identifies a particular MDB deployment in a particular application server.

This globalMDBName will be made available either through a special activation property set by the container, or by the
the container binding a String containing this name into a well-known place in JNDI.

Clustered application server instances
--------------------------------------

This brings us to (JMS_SPEC-73) (Define how messages from a topic are delivered to clustered application server instances).

I think this issue is closely linked to the issue of automatically setting subscriptionName so we need to consider it at
this point.

Essentially, the issue is this:

1. Consider a MDB that is deployed into a clustered application server (i.e. an application server which, for reasons of
scalability, is composed of multiple separate instances (JVMs))

2. The MDB is configured to consume messages from a topic.

When a particular message is added to the topic, how many copies of the message are delivered to the cluster? Does (1)
the whole cluster receive just one copy of the message, or does (2) each instance in the cluster receive one copy of the
message?

JMS does not currently define this - indeed Java EE generally does not say very much about clustering. However it is a
question that is frequently asked, and an issue that many application servers have attempted to provide a solution to.

I don't know how much I need to say here to explain my argument, so let me jump to some tentative proposals.

Proposals
---------

1. If a MDB application is deployed into a clustered application server then each message from a topic should be
delivered to a single MDB object somewhere in the cluster. That is, the entire cluster behaves as if uses a single
shared subscription on the topic.

2. A MDB application may be optionally configured to have the alternative behaviour. JMS will define an activation
property "shareSubscription". If this is set to *false* then one copy of each message from a topic should be delivered
to one MDB object in each application server instance. That is, each application server instance behaves as if it has a
separate subscription on the topic.

3. We will need to add some wording to reflect the fact that JMS (or Java EE) doesn't actually define what a cluster is,
and doesn't require the use of clustering.

Implementation
--------------

We will need to define what the application needs to do to control whether a topic subscription (either durable or
non-durable) is shared across the cluster or not.

Many application servers already support this as an option. Some do it by deliberately breaking the restriction on the
use of duplicate client identifiers, or the restriction that a topic subscription can have only one consumer.

JMS should aim to NOT break these existing facilities, or the way in which they are configured. However JMS should
define a standard way in which an application can define whether they want to enable or disable the sharing of
subscriptions across the cluster.

Since clustered application servers typically require every instance in the cluster to use the same application
configuration, we need to allow sharing and non-sharing of subscriptions to be configured without requiring each
instance to be configured differently (e.g. with a different subscription name or a different clientId).

Here's the proposal:

Proposal
--------

1. If the subscription is *durable*, then the subscription will be shared across the cluster if:

* subscriptionName is unset
* clientId is unset (since setting the same clientId in multiple instances would violate clientId uniqueness)

The resource adapter will automatically set subscriptionName to the globally-unique name of the MDB, which will ensure
that all instances use the same durable subscription. (Note that JMS 2.0 allows multiple consumers on the same durable
subscription, and no longer requires clientId to be set).

2. If the subscription is *non-durable*, then the subscription will be shared across the cluster if:

* subscriptionName is unset
* clientId is unset (since setting the same clientId in multiple instances would violate clientId uniqueness)

The resource adapter will automatically set subscriptionName to the globally-unique name of the MDB. This will be used
to set the *shared subscription name* that we have added to JMS 2.0. (Note that JMS 2.0 allows multiple consumers on the
same non-durable shared subscription).

HOW DOES the application disable this behaviour?

3. If the subscription is *durable*, then the subscription will NOT be shared across the cluster if:

* subscriptionName is unset
* clientId is unset (since setting the same clientId in multiple instances would violate clientId uniqueness)
* a special activation property shareSubscription is set to false

The resource adapter will automatically set subscriptionName to the globally-unique name of the MDB, concatenated with
the name of the instance within the cluster. This will ensure that all instances use a separate durable subscription.

2. If the subscription is *non-durable*, then the subscription will be shared across the cluster if:

* subscriptionName is unset
* clientId is unset (since setting the same clientId in multiple instances would violate clientId uniqueness)
* a special activation property shareSubscription is set to false

The resource adapter will automatically set subscriptionName to the globally-unique name of the MDB, concatenated with
the name of the instance within the cluster. This will be used to set the *shared subscription name* that we have added
to JMS 2.0. This will ensure that all instances use a separate durable subscription.

We may need something similar to support Java EE applications which use the JMS API to synchronously consume messages
rather than using MDBs.

Summary
-------

New activation property shareSubscription, set by the application and interpreted by the resource adapter

New properties globalMDBName and instanceName, set by the container and used by the resource adapter when to generate an
appropriate default subscriptionName. This might be passed to the resource adapter either as activation properties or as
entries in well-known locations in JNDI.

Next steps
----------

Before I work this up into a more detailed proposal, does anyone have any general comments?

Unfinished issues
-----------------

There are a number of unfinished issues:
* what are the valid chars and max length of globalMDBName and instanceName?
* what are the valid chars and max length of subscriptionName?
* how do we make this feature available to applications using the JMS API to create a consumer?

Thanks,

Nigel