Bug 734059 - If Message-driven bean used with topics, message delivered 15 times
Summary: If Message-driven bean used with topics, message delivered 15 times
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: Red Hat Enterprise MRG
Classification: Red Hat
Component: qpid-jca
Version: 2.0
Hardware: Unspecified
OS: Unspecified
urgent
high
Target Milestone: ---
: ---
Assignee: Jiri Sedlacek
QA Contact: MRG Quality Engineering
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2011-08-29 10:57 UTC by Jiri Sedlacek
Modified: 2015-08-02 23:43 UTC (History)
7 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2012-12-10 21:35:39 UTC


Attachments (Terms of Use)
reproducer maven project (1.93 KB, application/x-compressed-tar)
2011-09-01 07:40 UTC, Jiri Sedlacek
no flags Details
Updated examples to aid in testing (53.78 KB, application/java-archive)
2011-09-05 08:54 UTC, Weston M. Price
no flags Details

Description Jiri Sedlacek 2011-08-29 10:57:57 UTC
Description of problem:

If the javax.jms.Topic is used in message driven bean for receiving messages, the message is received 15 times (actually, the N-times, where N is the number of created instances of MDB). Also, on the side of qpid, there is created N queues for distributing message, each for one instance of MDB.

Version-Release number of selected component (if applicable):


How reproducible:

use eap-5.1.1 installation zip a the attached reproducer maven project
  
Actual results:

message is received 15 times

Expected results:

should be received only once

Additional info:

Although it's not specified in EJB 3 standard, expected behavior is also behavior of other messaging providers (HornetQ, JbossMessaging) and other application servers (Websphere)

Comment 1 Jiri Sedlacek 2011-09-01 07:40:55 UTC
Created attachment 520964 [details]
reproducer maven project

Comment 2 Weston M. Price 2011-09-01 13:58:02 UTC
I need more information, please provide the configuration you are using.

Comment 3 Weston M. Price 2011-09-01 13:58:21 UTC
Sorry, didn't see the attachment, I will review.

Comment 4 Rajith Attapattu 2011-09-01 15:11:38 UTC
First of all please do not use the old BURL syntax.
All of our documentation is now using the new addressing syntax.

Since MRG 1.3 the default syntax has been address strings - not BURL!

For completeness, the following BURL is not a topic!
destinationAddress=direct://amq.direct//topic.Hello?routingkey='topic.Hello'

If you wanted to use a topic is should have been,
 destinationAddress=topic://amq.topic//topic.Hello?routingkey='topic.Hello'

Again I stress that we need to keep testing JMS and JCA with destination configured using the address syntax since that is what we have put in our documentation.

Comment 5 Jiri Sedlacek 2011-09-02 07:56:59 UTC
As far as I was able to debug the code, the jca adapter needs to use only binding URL, no address syntax.

Comment 6 Weston M. Price 2011-09-02 09:10:21 UTC
Please see

https://bugzilla.redhat.com/show_bug.cgi?id=700494

However, even with this bug, you should still use ADDR syntax. As per Rajith's comments, ADDR is the default mechanism and the underlying JMS client will correctly handle ADDR destination strings. 

Again, this appears to be misconfigured either way since you want a topic, but as Rajith points out your original string this is not configured correctly.

Comment 7 Jiri Sedlacek 2011-09-02 11:39:27 UTC
Weston, 

the functionality to use ADDR syntax IS NOT present in JCA adapter (and won't be even in 2.0.4 version, as mention un Bug 700494), so we definitely need a way how to properly configure jms queue and topic with BURL syntax. 

Please provide functional and verified examples, because our testning is blocked by that.



This issue (as was reported) is not related to topic or direct exchange from the qpid point of view, the same situation is when I use amq.topic in BURL. 
The only difference between direct and topic exchange is in delivering messages to queues regarding to routing_key and binding_key. This is qpid point of view.
The topic in JMS api has completely different meaning.
The problem is, that if MDB is deployed and bound to JMS topic, the 15 instances of the class are created and each instance obviously has it's own consumer and own connection (and it's own queue on the qpid side), and from the behavior of JMS topic, the message is delivered to every consumer currently connected. But expected behavior is just one message delivered to MDB, even if 15 instances of the same MDB are created.

Comment 8 Weston M. Price 2011-09-02 13:20:01 UTC
'But expected behavior is just one message delivered to MDB, even if
15 instances of the same MDB are created.'

For queues this is correct, for topics it is not. The pub/sub messaging domain is designed to allow messages to be delivered to multiple subscribers, that is in fact what pub/sub means. For MDB's, every MDB instance that has 'subscribed' to a topic will receive the message. If you want only once delivery, you would use a Queue (point-to-point domain) not a Topic.

You can limit the number of sessions for the adapter by setting the property:


@ActivationConfigProperty(propertyName = "maxSession", propertyValue = "1")

This will give you the behavior that you want, but again, it is not applicable for pub/sub as in the above example, what you really want to use is a Queue, not a Topic since you only want one consumer/listener to receive the message.

Comment 9 Weston M. Price 2011-09-05 08:54:26 UTC
I am attaching jca-examples.jar which is a rework of the JCA examples providing
much more realistic examples for Queue/Topics, syntax etc. This should give
better examples that what was previously provided. There is a BZ for this
735322, but I thought I would get the work out early so you can start taking a
look. 

Alternatively you can check it out from GitHub as well:

git://github.com/astitcher/qpid-jca.git

branch is wp-BZ-735322

Comment 10 Weston M. Price 2011-09-05 08:54:56 UTC
Created attachment 521455 [details]
Updated examples to aid in testing

Comment 11 Weston M. Price 2011-09-05 09:49:36 UTC
Note, a word about Queues/Topics and JCA in general:

As previously mentioned, Topics are used for the pub/sub style of messaging. As such, ANY subscriber to a particular topic receives the message as opposed to queues. This would be the case independent of JEE and JCA. This is basic JMS. If you have two subscribers to a particular topic BOTH those subscribers will receive the message. 

 In EE, the EJB container is responsible for managing message listeners (in our case, JMS MDB's). The container creates (n) number of MDB instances for each deployment, manages their lifecycle etc. In the case of an MDB listening/subscribing to a Topic, ALL instances of the MDB will receive a message. This is how Topics, and pub/sub in general works. Again, this is standard JMS.  This is not the case for queues, where one, and only one, consumer will receive the message (this assumes of course you have things configured correctly). 

The MRG-JCA adapter is responsible for 'adapting' the MRG Broker into a JEE environment. When it comes to the delivery of messages, the ONLY API the JCA adapter uses is is JMS. There is no inherent JCA 'magic' under the hood. 

The process is pretty simple conceptually:

1) When an MDB is deployed, the EJB container passes the ActivationSpec to the JCA adapter. This is usually referred to as 'activating' the endpoint (endpoint is the MDB basically).


2) The adapter uses the properties of the activation spec to configure the necessary objects to support delivery to the MDB. Note, this is roughly the same process as you would execute when setting up a MessageListener outside of a JEE environment. 

    a) Setup ConnectionFactory (in JEE, this usually means just pulling it from JNDI)
    b) Setup Destination (in JEE, this usually means just pulling it from JNDI)
    c) Create the Connection
    d) Create the Session
    e) Register an exception listener
    f) Create a consumer or describer as per the type of Destination (i.e. queue or topic respectively)
    g) Set's the MessageListener on the  consumer or subscriber
    i) Set's up XA support if necessary (or local transaction)
    j) Start's the connection allowing incoming messages.

That's it. So, again, with JCA itself is a complex subject, in the context of JMS it's really quite understandable. If your ever in doubt about what JCA/JMS is, simply think about what would happen outside of the context of JCA. Returning to our original point, if you have multiple subscribers to a Topic, then each on of those subscribers is going to receive a message for that Topic. You have multiple consumers on  Queue, only one will get the message.

Comment 12 Weston M. Price 2011-09-05 09:51:17 UTC
If the above explanation(s) are sufficient, please close this issue.

Comment 13 Jiri Sedlacek 2011-09-05 10:18:23 UTC
Weston, 

I'm aware of how pub/sub model with jms topics works and I understand the whole process of deploying MDB (what is done and how). The problem is, that MRG JCA adapter behaves differently from JBossMessaging or HornetQ and this can be confusing for users/customers. 

I understand, that each instance of MDB (default is 15) is independently connected to qpid server and thus each one receives the message. I don't know the inner implementation of JBossMessaging or HornetQ, but MDB used with both of them, even if 15 instances of the same MDB is created (which is default number), receives one message from the jms topic just once (it's discussed also here: http://community.jboss.org/message/541041). 

I cannot decide which is correct, EJB specification lacks this case. But It probably will be better to have same behavior as all other messaging providers from our company, or document this feature clearly and carefully for customers to know what they should expect.

Comment 14 Weston M. Price 2011-09-05 10:40:51 UTC
Ah, ok, you mean DURABLE topics, you did not mention this. 

Unfortunately, for this configuration each subscriber requires a unique subscription id in the case of a durable topic. This is mandated by the JMS specification. Unfortunately, we do not implement this feature today in the JCA adapter where we would generate a unique subscription id. As such, this doesn't work out of the box. 

So, this most likely is a feature request since you can achieve the exact same semantics through the use of queues. It is somewhat questionable to have multiple subscribers for a durable topic to balance workload as again, you get this with queues anyway. 

However, it is indeed something we are lacking with durable topics.

Comment 15 Weston M. Price 2011-09-05 12:11:32 UTC
In thinking about this, the other way to achieve what you want is by what I mentioned before:

@ActivationConfigProperty(propertyName = "maxSession", propertyValue = "1")

When you set this, only one Session will be created as a result, your client_id and subscription name will be unique.  Note, this has nothing to do with the MDB instance pool, there are still multiple MDB instances since there isn't a 1-1 correspondence between Sessions and MDB instances. 

This will give you the behavior that you are looking for however, a few things to keep in mind again:

1) This is really non-standard behavior and just because HornetQ, or another JMS provider manages this, it's probably not enough to claim that this is a defect. 

2) The same effect can be achieved using queues which is really the 'correct' way to achieve this messaging style. 

3) Limiting the max sessions will also give you want you want as well, so I believe we can say we do 'support' this feature via configuration. 

If this is sufficient, please close this issue.

Comment 16 Jiri Sedlacek 2011-09-06 15:31:52 UTC
Weston, also oracle writes and does what I said: http://download.oracle.com/docs/cd/E12840_01/wls/docs103/ejb/message_beans.html 

ad 1/ this should be standard for us, if majority of our messaging providers does it. If we certify this for customers to be able to smoothly start using MRG, it should behave in the same way. You maybe don't agree with me, but this have to be resolved by PM. 

ad 2/ the same effect cannot be achieved by queues, if you need two different MDBs (maybe on different hosts) to receive one message, you need them to be connected to topic.

ad 3/ limiting the max sessions can affect performance, can't it?

Comment 17 Weston M. Price 2011-09-06 15:47:08 UTC
ad 1/
  Whether I disagree or not is really irrelevant. As you point out, this is a PM decision. We just don't do it today. In regards to other application servers, I am not sure if this is a valid argument as there are plenty of differences in regards to functionality between app servers as well as messaging providers. Again, this is just my opinion.


ad 2/
I'm not quite sure I follow. Two MDB's (both on different hosts), both configured to listen to a queue, one MDB will receive the message the other will not. Where these MDB's are located is irrelevant. 

The behavior that you are asking for, as far as I can tell, is to load balance across topic listeners pointing to one durable subscription to achieve the effect that only ONE instance of the MDB receives the message. Again, this is point-to-point behavior exactly and is the complete opposite to the way Topics work 

So, my real question is what exactly is the benefit of this topology configuration beyond the reason of 'If they do it, we should do it?' Again, if I am missing something, then I apologize.

ad 3
Yes, there is always a performance hit. It was simply mentioned as a 'sort of' workaround, that was all.

Comment 18 Weston M. Price 2011-09-06 15:51:36 UTC
Also, in reviewing the Oracle doc, I am looking for the place in the documentation that says:

'You can configure Topic listeners so as to only have only one subscriber receive the message versus every instance in the pool'...or something equivalent. 

From the doc you posted:

' In contrast to a point-to-point application, in a publish/subscribe model, a message is processed by one instance of each of the subscribing MDBs. Message “M1” is processed by an instance of MDB_A and an instance of MDB_B. Similarly, “M2” is processed by an instance of each of the subscribing MDBs.'

So, again, could you point to me in the doc where it says you can configure topic subscribers so that only one instance gets a message? This might help clarify when this would be useful.

Comment 19 Andrew Stitcher 2011-09-06 19:24:13 UTC
I think so far this discussion boils down to "Should this work be targeted at 2.0.4 as well as 2.2? or will doing it just for the later release suffice?"

Doing this for 2.0.4 would likely be somewhat different from doing it for 2.0.4 as the code bases have already diverged somewhat, it would likely double the implementation effort.

Comment 20 Jiri Sedlacek 2011-09-07 14:49:47 UTC
You selected the exact sentence from the oracle guide, which describes it. In pub/sub model, for each connected MDB just one instance receives message from topic, not all instances.

This could be useful, e.g. if you want to start two asynchronous servises by just one message, you have to send it to the topic and both two services will receive it a can do whatever with it. With queue, it's not possible, just one of these services will receive the message and you don't know which.

Comment 21 Weston M. Price 2011-09-15 16:40:22 UTC
As a result of the above discussion, while we don't do this today, I agree with the reporter that this will be a valid feature in the future. As such, I am changing the devel_ack flag to devel_ack- and changing the target milestone to 2.0.10.

Comment 22 Weston M. Price 2011-12-16 18:03:40 UTC
After doing some more investigation I have a status update in regards to this issue. In talking with QE, HornetQ team etc, I believe we currently do not implement this correctly. 

For JEE MDB's subscribing to a non-durable, JMS topic, the behavior SHOULD be that the message gets delivered only once. This is not happening because on deployment, we create n consumers per n number of sessions (by default, we create 15). Each one of these consumers/subscribers creates a uniquely identified temp queue which in turn causes a single message to be delivered 15 times (as the original BZ stated). 

There are three workarounds/solutions:

1) Limit the number of sessions to 1 for Topics. 

2) Use queues instead of Topics

3) A new solution would be to create the Topic with the following syntax, or something similar:

destinationAddress=amq.topic/hello.Topic;{link:{name:hello-topic,x-subscribe:{exclusive:false}}}

using the above syntax we set it up the link to where the same name is shared across multiple sessions and the topic is not exclusive. This is in effect the same default behavior as queues, but will work in the case of MDB's and Topics to get the equivalent behavior of HornetQ/JBM etc. HornetQ does something similar in their JCA/JMS client, here we are simply specifying this behavior to the server.

Approach #3 would be preferred...HOWEVER, currently the JMS client does not allow for non-exclusive Topics 

>>
if (dest.getDestSyntax() == AMQDestination.DestSyntax.ADDR)
        {
            if (dest.getAddressType() == AMQDestination.TOPIC_TYPE)
            {
                return true;
            }
            else
            {                
                return dest.getLink().getSubscription().isExclusive();
            }
        }
<<

so this option is not available at this time. I am going to file a JIRA upstream and a new BZ to allow for this option and link it as a dependency for this issue. 

Good work on QE's part again in identifying a discrepancy in the JMS providers behavior. Similarly, our documentation should be updated to identify the differences in behavior and the proposed workarounds. Once #3 gets implemented, I believe this should be the default behavior for our MDB/Topic configurations in the examples.

Comment 23 Weston M. Price 2011-12-16 20:29:39 UTC
In talking with Rajith, the following string would work as well in getting around the exclusive 'bug'

 destinationAddress=hello-topic; {create: always, link : {x-bindings:[{exchange: 'amq.topic', key : 'hello.Topic'}]}} 


You can use this syntax to test and close this bug.

We are going to rethink the process we use for creating/managing topics in a later release.

Comment 24 Jiri Sedlacek 2011-12-20 07:46:40 UTC
I tested this string

 destinationAddress=hello-topic; {create: always, link :
{x-bindings:[{exchange: 'amq.topic', key : 'hello.Topic'}]}} 

and it solves the problem with 15 messages to one MDB (tested version 3.0) on topic.

Comment 25 Rajith Attapattu 2012-01-26 19:59:53 UTC
Jiri, could you please have a look and mark verified ?

I'm moving this to modified as the latest JMS rpms (or any recent rpms with addressing support) can support the above string.

Rajith


Note You need to log in before you can comment on or make changes to this bug.