ActiveMQ
  1. ActiveMQ
  2. AMQ-3746

Non Durable Topic subscription with prefetch=0, MessageConsumer.receivenowait() (or MessageConsumer.receive(timeout) hangs indefinitely

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 5.5.1
    • Fix Version/s: 5.8.0
    • Component/s: Broker
    • Labels:
      None

      Description

      Non Durable Topic subscription with prefetch=0, MessageConsumer.receivenowait() (or MessageConsumer.receive(timeout) hangs indefinitely.

      I get the following thread dump

      "main" prio=5 tid=7f996d000000 nid=0x105bc3000 in Object.wait() [105bc1000]
         java.lang.Thread.State: WAITING (on object monitor)
      	at java.lang.Object.wait(Native Method)
      	- waiting on <7f39f1b30> (a java.lang.Object)
      	at java.lang.Object.wait(Object.java:485)
      	at org.apache.activemq.SimplePriorityMessageDispatchChannel.dequeue(SimplePriorityMessageDispatchChannel.java:87)
      	- locked <7f39f1b30> (a java.lang.Object)
      	at org.apache.activemq.ActiveMQMessageConsumer.dequeue(ActiveMQMessageConsumer.java:468)
      	at org.apache.activemq.ActiveMQMessageConsumer.receiveNoWait(ActiveMQMessageConsumer.java:621)
      	at org.apache.activemq.usecases.TopicSubscriptionZeroPrefetchTest.testTopicConsumerPrefetchZero(TopicSubscriptionZeroPrefetchTest.java:71)
      

      It seems the TopicSubscription does not support "pullMessage".

      This only appears to impact Non Durable Topic Subscriptions. Durable Topic Subscriptions with prefetch=0 do NOT exhibit this behavior.

      1. AMQ-3746.txt
        13 kB
        Timothy Bish
      2. APotentialFixForAMQ-3746.patch
        5 kB
        Pat Fox
      3. TopicSubscriptionZeroPrefetchTest.patch
        4 kB
        Pat Fox

        Activity

        Hide
        Pat Fox added a comment -

        attached a new junit testcase to illustrate issue.

        Show
        Pat Fox added a comment - attached a new junit testcase to illustrate issue.
        Hide
        Pat Fox added a comment -

        Perhaps rather than reaching a hanging state, the MessageConsumer could "fail fast" at creation time if prefetch=0 for non durable topic subscribers.

        To that effect, I have attached "APotentialFixForAMQ-3746.patch" where the ActiveMQMessageConsumer constructor does the following check.

        	// AMQ-3746
        	// if prefetch set to zero for Non Durable topic Consumer, throw a JMS Exception.
        	if(this.getPrefetchNumber() == 0 && info.getDestination().isTopic() && !isDurableSubscriber()){
                throw new JMSException("Cannot have a prefetch size of zero for a Non Durable Topic Subscriber");
            }
        

        I hope the above check should isolate just Non Durable Topic consumers with prefetch=0, perhaps someone could review it? Maybe there is a cleverer way to resolve this issue?

        patch created off lastest revision (1295087)

        Show
        Pat Fox added a comment - Perhaps rather than reaching a hanging state, the MessageConsumer could "fail fast" at creation time if prefetch=0 for non durable topic subscribers. To that effect, I have attached "APotentialFixForAMQ-3746.patch" where the ActiveMQMessageConsumer constructor does the following check. // AMQ-3746 // if prefetch set to zero for Non Durable topic Consumer, throw a JMS Exception. if ( this .getPrefetchNumber() == 0 && info.getDestination().isTopic() && !isDurableSubscriber()){ throw new JMSException( "Cannot have a prefetch size of zero for a Non Durable Topic Subscriber" ); } I hope the above check should isolate just Non Durable Topic consumers with prefetch=0, perhaps someone could review it? Maybe there is a cleverer way to resolve this issue? patch created off lastest revision (1295087)
        Hide
        Pat Fox added a comment -

        After applying "APotentialFixForAMQ-3746.patch" I noticed a change in exception behavior around the "MessageListener" case. Before applying the patch ActiveMQMessageConsumer.setMessageListener()
        throws the JMSException below when prefetch=0.

        before patch:

        javax.jms.JMSException: Illegal prefetch size of zero. This setting is not supported for asynchronous consumers please set a value of at least 1
        	at org.apache.activemq.ActiveMQMessageConsumer.setMessageListener(ActiveMQMessageConsumer.java:417)
        	...
        

        after applying the patch the following exception is thrown when creating the ActiveMQMessageConsumer before ActiveMQMessageConsumer.setMessageListener() can be called.

        javax.jms.JMSException: Cannot have a prefetch size of zero for a Non Durable Topic Subscriber
        	at org.apache.activemq.ActiveMQMessageConsumer.<init>(ActiveMQMessageConsumer.java:245)
        	at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:1134)
        	at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:1078)
        	at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:991)
        	at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:964)
        	...
        

        Although it results in the same overall outcome, it does change the existing (correct) exception behavior.

        Hence not sure if "Fail Fast" in "APotentialFixForAMQ-3746.patch" is the best approach.

        Show
        Pat Fox added a comment - After applying "APotentialFixForAMQ-3746.patch" I noticed a change in exception behavior around the "MessageListener" case. Before applying the patch ActiveMQMessageConsumer.setMessageListener() throws the JMSException below when prefetch=0. before patch: javax.jms.JMSException: Illegal prefetch size of zero. This setting is not supported for asynchronous consumers please set a value of at least 1 at org.apache.activemq.ActiveMQMessageConsumer.setMessageListener(ActiveMQMessageConsumer.java:417) ... after applying the patch the following exception is thrown when creating the ActiveMQMessageConsumer before ActiveMQMessageConsumer.setMessageListener() can be called. javax.jms.JMSException: Cannot have a prefetch size of zero for a Non Durable Topic Subscriber at org.apache.activemq.ActiveMQMessageConsumer.<init>(ActiveMQMessageConsumer.java:245) at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:1134) at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:1078) at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:991) at org.apache.activemq.ActiveMQSession.createConsumer(ActiveMQSession.java:964) ... Although it results in the same overall outcome, it does change the existing (correct) exception behavior. Hence not sure if "Fail Fast" in "APotentialFixForAMQ-3746.patch" is the best approach.
        Hide
        Timothy Bish added a comment -

        Another potential fix is to actually allow TopicSubscription to work with a zero prefetch. A pullMessage request could open a window to allow one topic message to get dispatched to the topic inside the pull time window given. This basically allows the consumer to always be a slow consumer, and messages are stored based on the maxPendingMessageLimit. Not sure what the use case for that would be but its possible. Here's a rough patch that adds this, not tested very heavily.

        Show
        Timothy Bish added a comment - Another potential fix is to actually allow TopicSubscription to work with a zero prefetch. A pullMessage request could open a window to allow one topic message to get dispatched to the topic inside the pull time window given. This basically allows the consumer to always be a slow consumer, and messages are stored based on the maxPendingMessageLimit. Not sure what the use case for that would be but its possible. Here's a rough patch that adds this, not tested very heavily.
        Hide
        Claus Ibsen added a comment -

        Tim, sounds like a good idea.

        Maybe try to revisit your patch for the 5.8 release.

        Show
        Claus Ibsen added a comment - Tim, sounds like a good idea. Maybe try to revisit your patch for the 5.8 release.
        Hide
        Gary Tully added a comment -

        that reads very like the use case for a retroactive consumer. I would expect a poll to only work if there is something pending in the retroactive buffer. But a poll should not block for ever. That is really a bug.

        Show
        Gary Tully added a comment - that reads very like the use case for a retroactive consumer. I would expect a poll to only work if there is something pending in the retroactive buffer. But a poll should not block for ever. That is really a bug.
        Hide
        Timothy Bish added a comment -

        Fixed on trunk

        Show
        Timothy Bish added a comment - Fixed on trunk

          People

          • Assignee:
            Timothy Bish
            Reporter:
            Pat Fox
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development