9 Replies Latest reply on Mar 1, 2004 7:22 PM by adrian.brock

    Closing receiver on client causes server exception

    krsmes

      I have a standard configuration where the client sends a message to a named queue and then picks up a response using a selector from another named queue.

      If I call close() on my receiver (QueueReceiver) after getting the response then I get the following exception sporatically on the server. If I don't call close() on the receiver it eventually builds up too many threads on the client and I get an out-of-memory error (similar to http://www.jboss.org/index.html?module=bb&op=viewtopic&t=46053).

      The exception does not seem to cause any ill side effect but is there something I'm doing/not-doing to cause it?

      15:26:29,126 WARN [OILServerILService] Client request resulted in a server exception:
      javax.jms.JMSException: The provided subscription does not exist
       at org.jboss.mq.server.ClientConsumer.acknowledge(ClientConsumer.java:315)
       at org.jboss.mq.server.JMSDestinationManager.acknowledge(JMSDestinationManager.java:529)
       at org.jboss.mq.server.JMSDestinationManager.acknowledge(JMSDestinationManager.java:513)
       at org.jboss.mq.server.JMSServerInterceptorSupport.acknowledge(JMSServerInterceptorSupport.java:198)
       at org.jboss.mq.server.TracingInterceptor.acknowledge(TracingInterceptor.java:481)
       at org.jboss.mq.server.JMSServerInvoker.acknowledge(JMSServerInvoker.java:198)
       at org.jboss.mq.il.oil.OILServerILService$Client.run(OILServerILService.java:245)
       at java.lang.Thread.run(Thread.java:534)


        • 1. Re: Closing receiver on client causes server exception

          I see no relation and the referenced topic.
          Post your code or an example that reproduces the problem.

          Most likely you are closing stuff in the wrong order.

          Regards,
          Adrian

          • 2. Re: Closing receiver on client causes server exception
            krsmes

            Here is the code snippits in proper sequence (this is all on the client side)

            // WHILE SENDING A MESSAGE:
            ...
            String id = message.getJMSMessageID();
            Queue rq = (Queue) message.getJMSReplyTo();
            QueueResponse receiver = JMS.createReceiver((QueueConnection) getConnection(),
             (QueueSession) getSession(), rq, this, "JMSCorrelationID = '"+id+"'");
            sentMessages.put(id, receiver);
            ...
            
            // IN onMessage()
            String corr = message.getJMSCorrelationID();
            removeSentMessage(corr);
            ...
            
            // REMOVE SENT MESSAGE
            protected boolean removeSentMessage(String id)
             throws javax.jms.JMSException
            {
             QueueReceiver receiver = (QueueReceiver) sentMessages.remove(id);
            
             if (receiver != null)
             {
             receiver.close();
             }
             return (receiver != null);
            }
            


            If I don't call "receiver.close()" I never get any exceptions in the server log and it functions ok as long as the client is not sending messages at a high rate. If the client is sending messages at a high rate then the thread count skyrockets and eventually throws an out-of-memory error.

            If I do call "receiver.close()" then the client functions just fine, even at a high rate of messages (no thread/memory problems). But I get those sporatic exceptions on the jboss server log (javax.jms.JMSException: The provided subscription does not exist) - sporadic being 1 exception for every 500-1000 messages.

            I am using a single connection and single session, both the send and response queues are fixed/named (not temporary) the client is on a separate machine than the server. The server is running jboss 3.2.3 under jdk 1.4.2.







            • 3. Re: Closing receiver on client causes server exception

              You don't show the full lifecycle of the receiver, you only show its removal.

              Regards,
              Adrian

              • 4. Re: Closing receiver on client causes server exception
                krsmes

                 

                "adrian@jboss.org" wrote:
                You don't show the full lifecycle of the receiver, you only show its removal.


                Hmm... I've posted all the snippits of code that deal with the receiver so I'm not sure what to add.

                1) the receiver is created when a message is sent, it is created against a fixed queue using a selector against the ID of the message being sent.

                2) the receiver is "held" in a Map, keyed on the ID of the message that was sent.

                3) when a reply (to the sent message) comes in to onMessage the receiver is retrieved from the Map and closed.

                Hope that helps.

                • 5. Re: Closing receiver on client causes server exception

                  It's not a test. Give us enough information to solve your problem.
                  A few code snippets in isolation are useless. e.g. closing a session closes the receiver.

                  Regards,
                  Adrian

                  • 6. Re: Closing receiver on client causes server exception
                    krsmes

                     

                    public void testCodeInIsolation()
                     throws Exception
                    {
                     Context context = new InitialContext();
                     QueueConnectionFactory qcf = (QueueConnectionFactory) context.lookup("ConnectionFactory");
                     final QueueConnection qc = qcf.createQueueConnection();
                     final QueueSession qs = qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
                     final Queue sendQ = (Queue) context.lookup("queue/xx-MessageTest");
                     final Queue replyQ = (Queue) context.lookup("queue/xx-ReturnMessageTest");
                    
                     final Map sentMessages = Collections.synchronizedMap(new HashMap());
                    
                     final MessageListener listener =
                     new MessageListener()
                     {
                     public void onMessage(Message message)
                     {
                     try
                     {
                     TextMessage tmessage = (TextMessage) message;
                     String msgcontent = tmessage.getText();
                     String id = message.getJMSMessageID();
                     String corr = message.getJMSCorrelationID();
                     System.out.println("received "+id+" in reply to "+corr+" containing: "+ msgcontent);
                     QueueReceiver receiver = (QueueReceiver) sentMessages.remove(corr);
                    //**** receiver.close();
                     }
                     catch (JMSException e)
                     {
                     e.printStackTrace();
                     }
                     }
                     };
                    
                     Runnable run =
                     new Runnable()
                     {
                     public void run()
                     {
                     try
                     {
                     for (int cntr = 0; cntr < 1000; cntr++)
                     {
                     String msgcontent = "test-" + cntr;
                     TextMessage message = qs.createTextMessage(msgcontent);
                     message.setJMSReplyTo(replyQ);
                    
                     QueueSender sender = qs.createSender(sendQ);
                     sender.send(message);
                     sender.close();
                     String id = message.getJMSMessageID();
                    
                     QueueReceiver receiver = qs.createReceiver(replyQ, "JMSCorrelationID = '"+id+"'");
                     receiver.setMessageListener(listener);
                     qc.start(); // i understand this call is only necessary once but outside of this isolation test this is the way it is called
                    
                     sentMessages.put(id, receiver);
                     }
                     }
                     catch (JMSException e)
                     {
                     e.printStackTrace();
                     }
                     }
                     };
                    
                     Thread[] t = new Thread[3];
                     t[0] = new Thread(run);
                     t[1] = new Thread(run);
                     t[2] = new Thread(run);
                     t[0].start();
                     t[1].start();
                     t[2].start();
                     while (t[0].isAlive() || t[1].isAlive() || t[2].isAlive())
                     Thread.sleep(250);
                    
                     while (!sentMessages.isEmpty())
                     Thread.sleep(250);
                    
                     qs.close();
                     qc.close();
                    }
                    


                    The above test reproduced what I am experiencing. On there server side there is just a simple Message Driven Bean listening to xx-MessageTest and return responses containing the contents of the message to xx-ReturnMessageTest.

                    The line in question is the one commented out with "//****" -- if that line is left out then the server logs look normal but the client process eats up 3000 threads before finishing. If that line is in place then the client process thread count stays within reason but the server throws the "javax.jms.JMSException: The provided subscription does not exist" exception ("WARN") frequently.

                    • 7. Re: Closing receiver on client causes server exception

                      You are closing the receiver from inside itself.

                      After onMessage() finishes, it will do message.acknowledge() - AUTO_ACKNOWLEDGE
                      which will fail because receiver.close() already closed the subscription.

                      Regards,
                      Adrian

                      • 8. Re: Closing receiver on client causes server exception
                        krsmes

                        Ok, that is helpful.

                        But if I don't close it, it doesn't look like anything else does either -- the client process' thread count shoots all the way up to 3000.

                        Is it normal to not close it?

                        • 9. Re: Closing receiver on client causes server exception

                          Use client acknowledge.

                          Also consider what happens if the server never responds? i.e. consider a timeout.

                          Regards,
                          Adrian