Uploaded image for project: 'ActiveMQ Classic'
  1. ActiveMQ Classic
  2. AMQ-5262

ActiveMQ hangs on shutdown when JMS Bridge is created

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Minor
    • Resolution: Fixed
    • 5.9.0, 5.9.1, 5.10.0
    • 5.10.1, 5.11.0
    • Broker
    • None

    Description

      We are having a problem with ActiveMQ hanging on shutdown. Here is the scenario, we have a stand alone application that runs an embedded ActiveMQ which creates a JMS Queue Bridge via Spring configs. When we call shutdown, the TCPTransport that connects the JMS Queue Bridge does not shutdown, it hangs on java.net.SocketInputStream.socketRead0().

      java.lang.Thread.State: RUNNABLE
      	at java.net.SocketInputStream.socketRead0(Native Method)
      	at java.net.SocketInputStream.read(SocketInputStream.java:129)
      	at org.apache.activemq.transport.tcp.TcpBufferedInputStream.fill(TcpBufferedInputStream.java:50)
      	at org.apache.activemq.transport.tcp.TcpTransport$2.fill(TcpTransport.java:604)
      	at org.apache.activemq.transport.tcp.TcpBufferedInputStream.read(TcpBufferedInputStream.java:58)
      	at org.apache.activemq.transport.tcp.TcpTransport$2.read(TcpTransport.java:589)
      	at java.io.DataInputStream.readInt(DataInputStream.java:370)
      	at org.apache.activemq.openwire.OpenWireFormat.unmarshal(OpenWireFormat.java:275)
      	at org.apache.activemq.transport.tcp.TcpTransport.readCommand(TcpTransport.java:221)
      	at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:213)
      	at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:196)
      	at java.lang.Thread.run(Thread.java:662)
      

      Digging around on the forums and the issue tracker, the work around seems to add a parameter to the URI (Ex - tcp://localhost:60606?daemon=true).

      According to this StackOverflow posting (http://stackoverflow.com/questions/2213340/what-is-daemon-thread-in-java) which quotes from Java Concurrency in Practice

      • When a new thread is created it inherits the daemon status of its parent.
      • Normal thread and daemon threads differ in what happens when they exit. When the JVM halts any remaining daemon threads are abandoned: *finally blocks are not executed*, stacks are not unwound - JVM just exits. Due to this reason daemon threads should be used sparingly and it is dangerous to use them for tasks that might perform any sort of I/O.

      So, making the Socket that connects the JMS Queue Bridge a Daemon thread, seems to be the wrong solution.

      I was trying to debug the initialization of ActiveMQ, and noticed the org.apache.activemq.network.jms.JmsConnector class has a stop() method on it. I believe this class creates the connection for the JMS Bridge, right? If so, the stop method does not seem to shutdown the connection properly.

      public void stop() throws Exception {
      
              if (started.compareAndSet(true, false)) {
      
                  ThreadPoolUtils.shutdown(connectionSerivce);
                  connectionSerivce = null;
      
                  for (DestinationBridge bridge : inboundBridges) {
                      bridge.stop();
                  }
                  for (DestinationBridge bridge : outboundBridges) {
                      bridge.stop();
                  }
                  LOG.info("JMS Connector {} stopped", getName());
              }
              
      }
      

      The question I have is why is the stop() method relying on the ThreadPoolUtils.shutdown(connectionSerivce) and NOT calling close() on the Connections first? For example:

      public void stop() throws Exception {
      
              if (started.compareAndSet(true, false)) {
      
      			foreignConnection.get().close();
      			localConnection.get().close();
      			
                  ThreadPoolUtils.shutdown(connectionSerivce);
                  connectionSerivce = null;
      
                  for (DestinationBridge bridge : inboundBridges) {
                      bridge.stop();
                  }
                  for (DestinationBridge bridge : outboundBridges) {
                      bridge.stop();
                  }
                  LOG.info("JMS Connector {} stopped", getName());
              }
              
      }
      

      It was a little difficult to follow the code, so I may be missing something. BUT shouldn't the connections close first? Or am I looking in the wrong place.

      I have created a small project that creates this scenario.
      https://github.com/pminearo/activemq-shutdown-bug.git

      This was done with ActiveMQ 5.9. Though, since this bug has been around for quite some time, it most likely is still in 5.10, 5.11, and 6.0.

      Attachments

        Activity

          People

            Unassigned Unassigned
            pminearo Peter Minearo
            Votes:
            1 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: