activemq-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Stirling Chow (JIRA)" <j...@apache.org>
Subject [jira] [Created] (AMQ-4148) Static subscriptions from network bridges do not respect TTL (off by one in calculation), resulting in duplicate consumers.
Date Wed, 31 Oct 2012 06:23:14 GMT
Stirling Chow created AMQ-4148:
----------------------------------

             Summary: Static subscriptions from network bridges do not respect TTL (off by
one in calculation), resulting in duplicate consumers.
                 Key: AMQ-4148
                 URL: https://issues.apache.org/jira/browse/AMQ-4148
             Project: ActiveMQ
          Issue Type: Bug
    Affects Versions: 5.8.0
            Reporter: Stirling Chow


Symptom
=======
The remote broker path is not set on network consumers that result from static subscriptions;
as a result, they are forwarded to other bridges even when the network TTL on the bridges
is 1.  In an n+1 hub-and-spoke network, the next broker to join receives n subscriptions instead
of 1.

Cause
=====
A consumer for a static subscriptions is created by the following code:

{code:title=DemandForwardingBridgeSupport.java}
private void startLocalBridge() throws Throwable {
...
    if (!disposed.get()) {
            setupStaticDestinations();
        } else {
            LOG.warn("Network connection between " + localBroker + " and " + remoteBroker
+ "(" + remoteBrokerName + ") was interrupted during establishment.");
        }
    }
}

/**
 * Subscriptions for these destinations are always created
 */
protected void setupStaticDestinations() {
...
            DemandSubscription sub = createDemandSubscription(dest);
            try {
                addSubscription(sub);
            } catch (IOException e) {
                LOG.error("Failed to add static destination " + dest, e);
            }
            if (LOG.isTraceEnabled()) {
                LOG.trace("bridging messages for static destination: " + dest);
            }
        }
    }
}

final protected DemandSubscription createDemandSubscription(ActiveMQDestination destination)
{
    ConsumerInfo info = new ConsumerInfo();
    info.setDestination(destination);

    // the remote info held by the DemandSubscription holds the original consumerId,
    // the local info get's overwritten
    info.setConsumerId(new ConsumerId(localSessionInfo.getSessionId(), consumerIdGenerator.getNextSequenceId()));
    DemandSubscription result = null;
    try {
        result = createDemandSubscription(info);
    } catch (IOException e) {
        LOG.error("Failed to create DemandSubscription ", e);
    }
    return result;
}
{code}

Note how the broker path is *not* set on the {{ConsumerInfo}} that is used for the subscription.
 

In contrast, a consumer for a dynamic subscription does have its broker path updated to indicate
that it is from a remote broker:

{code:title=DemandForwardingBridgeSupport.java}
protected void serviceRemoteCommand(Command command) {
    if (!disposed.get()) {
        try {
            if (command.isMessageDispatch()) {
                safeWaitUntilStarted();
                MessageDispatch md = (MessageDispatch) command;
                serviceRemoteConsumerAdvisory(md.getMessage().getDataStructure());
                ackAdvisory(md.getMessage());
...

private void serviceRemoteConsumerAdvisory(DataStructure data) throws IOException {
...
        if (addConsumerInfo(info)) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug(configuration.getBrokerName() + " bridged sub on " + localBroker
+ " from " + remoteBrokerName + " : " + info);
                }
            } else {
                if (LOG.isDebugEnabled()) {
                    LOG.debug(configuration.getBrokerName() + " Ignoring sub from " + remoteBrokerName
+ " as already subscribed to matching destination : " + info);
                }
            }
        }
...

protected boolean addConsumerInfo(final ConsumerInfo consumerInfo) throws IOException {
    boolean consumerAdded = false;
    ConsumerInfo info = consumerInfo.copy();
    addRemoteBrokerToBrokerPath(info);
...
{code}

Because of this difference, a static subscription will be forwarded to new bridges with a
{{null}} brokerPath while a dynamic subscription to the same queue will be forwarded with
a singleton brokerPath.  As a result, static subscriptions will be propagate one further hop
than their dynamic counterparts.  In the case of a network TTL of 1, the static subscription
consumers are unexpected propagated to new bridges, while the dynamic subscription consumers
are correctly suppressed.

Solution
========
There should be no logical difference between a network consumer created for a static subscription
vs. a dynamic subscription.  In either case, the bridge creates a consumer on behalf of the
remote broker.  As such, the consumer for a static subscription should have the remote broker
in its broker path because it represents a subscription from that remote broker (even if there
is no consumer).


--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Mime
View raw message