Uploaded image for project: 'Undertow'
  1. Undertow
  2. UNDERTOW-408

Network connection leak in asynchronous servlet

XMLWordPrintable

    • Hide

      The reproduced steps are as follows:

      Reproduced steps

      Step1. Compile the AsyncDemoServlet.java I have provided
      and export a war file called test.war.
      Step2. Deploy the test.war to the wildfly.
      Step3. check the current connection leak number and
      you will found the current connection leak number is 0
      Notice: you can use
      "lsof -p pid | grep "can't identify protocol" |wc -l"
      to check the current connection leak number.
      Step4. Access the asynchronous servlet application.
      i.e: if you deployed the test.war in your local application server,
      and your defalt http listener port is 8000, you can just enter the
      url as http://localhost:8080/test/asyncDemoServlet in your browser
      to access the web application.
      Step5. Click the "Esc" button in your keyboards in five seconds
      to terminated the http request.
      Step6. check the current connection leak number and
      you will found the current connection leak number has
      been increased by 1.
      Notice: you can use
      "lsof -p pid | grep "can't identify protocol" |wc -l"
      to check the current connection leak number.

      Show
      The reproduced steps are as follows: Reproduced steps Step1. Compile the AsyncDemoServlet.java I have provided and export a war file called test.war. Step2. Deploy the test.war to the wildfly. Step3. check the current connection leak number and you will found the current connection leak number is 0 Notice: you can use "lsof -p pid | grep "can't identify protocol" |wc -l" to check the current connection leak number. Step4. Access the asynchronous servlet application. i.e: if you deployed the test.war in your local application server, and your defalt http listener port is 8000, you can just enter the url as http://localhost:8080/test/asyncDemoServlet in your browser to access the web application. Step5. Click the "Esc" button in your keyboards in five seconds to terminated the http request. Step6. check the current connection leak number and you will found the current connection leak number has been increased by 1. Notice: you can use "lsof -p pid | grep "can't identify protocol" |wc -l" to check the current connection leak number.

      Phenomenon

      When the connection is suddenly terminated during the period we access the asynchronous servlet application, the connection will be leaked. However, the connection won't be leak when we access the synchronous servlet application.

      Some of the stacktrace are as follows:

      Stacktrace

      14:34:23,751 ERROR [io.undertow.request] (default task-22) Blocking request fail
      at io.undertow.servlet.spec.HttpServletResponseImpl.responseDone(HttpSer
      at io.undertow.servlet.spec.AsyncContextImpl$3.run(AsyncContextImpl.java
      at io.undertow.servlet.spec.AsyncContextImpl$6.run(AsyncContextImpl.java
      at io.undertow.servlet.spec.AsyncContextImpl$TaskDispatchRunnable.run(As
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor
      at java.lang.Thread.run(Thread.java:724) [rt.jar:1.7.0_25]
      Caused by: java.io.IOException: Connection reset by peer
      at sun.nio.ch.FileDispatcherImpl.write0(Native Method) [rt.jar:1.7.0_25]
      at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47) [rt.jar:1
      at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:94) [rt.jar:1.7.0
      at sun.nio.ch.IOUtil.write(IOUtil.java:51) [rt.jar:1.7.0_25]
      at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:466) [rt.ja
      at org.xnio.nio.NioSocketConduit.write(NioSocketConduit.java:150)
      at io.undertow.server.protocol.http.HttpResponseConduit.processWrite(Htt
      at io.undertow.server.protocol.http.HttpResponseConduit.flush(HttpRespon
      at io.undertow.conduits.AbstractFixedLengthStreamSinkConduit.flush(Abstr
      at org.xnio.conduits.ConduitStreamSinkChannel.flush(ConduitStreamSinkCha
      at io.undertow.channels.DetachableStreamSinkChannel.flush(DetachableStre
      at org.xnio.channels.Channels.flushBlocking(Channels.java:63)
      at io.undertow.servlet.spec.ServletOutputStreamImpl.close(ServletOutputS
      at io.undertow.servlet.spec.HttpServletResponseImpl.closeStreamAndWriter
      at io.undertow.servlet.spec.HttpServletResponseImpl.responseDone(HttpSer
      ... 6 more

      Here's the test war code you can used to reproduce this phenomenon:

      AsyncDemoServlet.java
      import java.io.IOException;
      import javax.servlet.AsyncContext;
      import javax.servlet.ServletException;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      @WebServlet(urlPatterns="/asyncDemoServlet",asyncSupported=true)
      public class AsyncDemoServlet extends HttpServlet {
          private static final long serialVersionUID = 1L;
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              response.setContentType("text/html;charset=UTF-8");
              //Execute the business logic in sub-thread.
              AsyncContext ctx = request.startAsync();
              new Thread(new Executor(ctx)).start();
          }
      
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doGet(request, response);
          }
      
          public class Executor implements Runnable {
              private AsyncContext ctx = null;
              public Executor(AsyncContext ctx){
                  this.ctx = ctx;
              }
              public void run(){
                  try {
                      ctx.getResponse().getOutputStream().write("aaa".getBytes());
                      //wait for 5 seconds to simulate the business logic.
                      Thread.sleep(5000);
                      ctx.getResponse().getOutputStream().flush();
                      ctx.complete();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }
      
      }
      

              sdouglas1@redhat.com Stuart Douglas (Inactive)
              jeremy_lv jeremy_lv lv (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

                Created:
                Updated:
                Resolved: