tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Thomas Boniface <tho...@stickyads.tv>
Subject Re: Async servlet and request recycling
Date Tue, 18 Oct 2016 08:55:03 GMT
Just a small correction, the callback was a bit weird. The correct one is
below (but that doesn't impact the behavior of the scenario)

@Override
public void completed(HttpResponse result) {
    try {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        ServletOutputStream out = res.getOutputStream();
        out.print("Hello world");
        out.flush();
        out.close();
    } catch (IOException e) {
    } finally {
        req.getAsyncContext().complete();
    }
}


2016-10-18 10:38 GMT+02:00 Thomas Boniface <thomas@stickyads.tv>:
>
> I think I managed to narrow things down a bit.
>
>
> I managed to reproduced locally the issue (it's not occuring 100% of the
time but it appears after a very few attempt for me). I created a really
basic webapps :
>
> package stickyads.tv;
>
> import org.apache.http.HttpResponse;
> import org.apache.http.client.methods.HttpGet;
> import org.apache.http.concurrent.FutureCallback;
> import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
> import org.apache.http.impl.nio.client.HttpAsyncClients;
>
> import javax.servlet.*;
> import javax.servlet.annotation.WebServlet;
> import java.io.IOException;
>
> @WebServlet(value="/hello", name="helloServlet", asyncSupported = true)
> public class HelloServlet extends GenericServlet {
>
>     private static final CloseableHttpAsyncClient httpclient =
HttpAsyncClients.createDefault();
>     static {
>         httpclient.start();
>     }
>
>     @Override
>     public void service(final ServletRequest req, final ServletResponse
res) throws ServletException, IOException {
>         req.startAsync();
>
>         HttpGet request = new HttpGet("http://www.apache.org/");
>         httpclient.execute(request, new FutureCallback<HttpResponse>() {
>             @Override
>             public void completed(HttpResponse result) {
>                 try {
>                     try {
>                         Thread.sleep(200);
>                     } catch (InterruptedException e) {
>                         e.printStackTrace();
>                     }
>
>                     ServletOutputStream out = res.getOutputStream();
>                     out.print("Hello world");
>                     out.flush();
>                     out.close();
>                 } catch (IOException e) {
>                     // this will generate an NPE
>                     req.getAsyncContext().complete();
>                 }
>             }
>
>             @Override
>             public void failed(Exception ex) {
>
>             }
>
>             @Override
>             public void cancelled() {
>
>             }
>         });
>     }
> }
>
> I deploy the war on tomcat 7.0.72 and then call it using a simple python
program that sends a request and closes the requests without waiting for a
response:
>
> import socket
>
> # create an INET, STREAMing socket
> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
> # now connect to the web server on port 80 - the normal http port
> s.connect(("127.0.0.1", 8080))
> s.send("GET /broken-pipe-1.0-SNAPSHOT/hello
HTTP/1.1\nHost:127.0.0.1\nX-Forwarded-For: 127.0.0.1\nX-Forwarded-Protocol:
http\n\n")
>
> This result in a broken pipe exception, a recycling of the async context
but no complete:
>
> INFO: An error occurred in processing while on a non-container thread.
The connection will be closed immediately
> java.net.SocketException: Broken pipe
>     at java.net.SocketOutputStream.$$YJP$$socketWrite0(Native Method)
>     at java.net.SocketOutputStream.socketWrite0(SocketOutputStream.java)
>     at
java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
>     at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
>     at
org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215)
>     at
org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480)
>     at
org.apache.coyote.http11.InternalOutputBuffer.endRequest(InternalOutputBuffer.java:159)
>     at
org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:761)
>     at org.apache.coyote.Response.action(Response.java:174)
>     at org.apache.coyote.Response.finish(Response.java:274)
>     at
org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:322)
>     at
org.apache.catalina.connector.CoyoteOutputStream.close(CoyoteOutputStream.java:108)
>     at stickyads.tv.HelloServlet$1.completed(HelloServlet.java:33)
>     at stickyads.tv.HelloServlet$1.completed(HelloServlet.java:26)
>     at
org.apache.http.concurrent.BasicFuture.completed(BasicFuture.java:119)
>     at
org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseCompleted(DefaultClientExchangeHandlerImpl.java:177)
>     at
org.apache.http.nio.protocol.HttpAsyncRequestExecutor.processResponse(HttpAsyncRequestExecutor.java:412)
>     at
org.apache.http.nio.protocol.HttpAsyncRequestExecutor.inputReady(HttpAsyncRequestExecutor.java:305)
>     at
org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:267)
>     at
org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
>     at
org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
>     at
org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:116)
>     at
org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:164)
>     at
org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:339)
>     at
org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:317)
>     at
org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:278)
>     at
org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
>     at
org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:590)
>     at java.lang.Thread.run(Thread.java:745)
>
> Oct 18, 2016 9:47:24 AM org.apache.catalina.core.AsyncContextImpl logDebug
> FINE: Req: 1f68c4e1  CReq: 3a716fa9  RP: 4c7aa6ad  Stage: 7  Thread:
http-bio-8080-exec-5  State:                  N/A  Method: recycle
 URI: /broken-pipe-1.0-SNAPSHOT/hello
>
> Here is also a tcpdump corresponding to this scenario:
>
> 09:47:43.916628 IP (tos 0x0, ttl 64, id 63341, offset 0, flags [DF],
proto TCP (6), length 60)
>     127.0.0.1.44078 > 127.0.0.1.8080: Flags [S], cksum 0xfe30 (incorrect
-> 0x0bcc), seq 3052296773, win 43690, options [mss 65495,sackOK,TS val
273198376 ecr 0,nop,wscale 7], length 0
> E..<.m@.@.EL..............ZE.........0.........
> .H.(........
> 09:47:43.916642 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto
TCP (6), length 60)
>     127.0.0.1.8080 > 127.0.0.1.44078: Flags [S.], cksum 0xfe30 (incorrect
-> 0x44d5), seq 705486696, ack 3052296774, win 43690, options [mss
65495,sackOK,TS val 273198376 ecr 273198376,nop,wscale 7], length 0
> E..<..@.@.<.............*..h..ZF.....0.........
> .H.(.H.(....
> 09:47:43.916653 IP (tos 0x0, ttl 64, id 63342, offset 0, flags [DF],
proto TCP (6), length 52)
>     127.0.0.1.44078 > 127.0.0.1.8080: Flags [.], cksum 0xfe28 (incorrect
-> 0x171a), seq 1, ack 1, win 342, options [nop,nop,TS val 273198376 ecr
273198376], length 0
> E..4.n@.@.ES..............ZF*..i...V.(.....
> .H.(.H.(
> 09:47:43.916917 IP (tos 0x0, ttl 64, id 63343, offset 0, flags [DF],
proto TCP (6), length 172)
>     127.0.0.1.44078 > 127.0.0.1.8080: Flags [P.], cksum 0xfea0 (incorrect
-> 0xbf79), seq 1:121, ack 1, win 342, options [nop,nop,TS val 273198376
ecr 273198376], length 120
> E....o@.@.D...............ZF*..i...V.......
> .H.(.H.(GET /broken-pipe-1.0-SNAPSHOT/hello HTTP/1.1
> Host:127.0.0.1
> X-Forwarded-For: 127.0.0.1
> X-Forwarded-Protocol: http
>
>
> 09:47:43.916923 IP (tos 0x0, ttl 64, id 29249, offset 0, flags [DF],
proto TCP (6), length 52)
>     127.0.0.1.8080 > 127.0.0.1.44078: Flags [.], cksum 0xfe28 (incorrect
-> 0x16a2), seq 1, ack 121, win 342, options [nop,nop,TS val 273198376 ecr
273198376], length 0
> E..4rA@.@...............*..i..Z....V.(.....
> .H.(.H.(
> 09:47:43.923131 IP (tos 0x0, ttl 64, id 63344, offset 0, flags [DF],
proto TCP (6), length 52)
>     127.0.0.1.44078 > 127.0.0.1.8080: Flags [F.], cksum 0xfe28 (incorrect
-> 0x16a0), seq 121, ack 1, win 342, options [nop,nop,TS val 273198377 ecr
273198376], length 0
> E..4.p@.@.EQ..............Z.*..i...V.(.....
> .H.).H.(
> 09:47:43.960144 IP (tos 0x0, ttl 64, id 29250, offset 0, flags [DF],
proto TCP (6), length 52)
>     127.0.0.1.8080 > 127.0.0.1.44078: Flags [.], cksum 0xfe28 (incorrect
-> 0x1695), seq 1, ack 122, win 342, options [nop,nop,TS val 273198387 ecr
273198377], length 0
> E..4rB@.@...............*..i..Z....V.(.....
> .H.3.H.)
> 09:47:44.380384 IP (tos 0x0, ttl 64, id 29251, offset 0, flags [DF],
proto TCP (6), length 179)
>     127.0.0.1.8080 > 127.0.0.1.44078: Flags [P.], cksum 0xfea7 (incorrect
-> 0xe005), seq 1:128, ack 122, win 342, options [nop,nop,TS val 273198492
ecr 273198377], length 127
> E...rC@.@...............*..i..Z....V.......
> .H...H.)HTTP/1.1 200 OK
> Server: Apache-Coyote/1.1
> Transfer-Encoding: chunked
> Date: Tue, 18 Oct 2016 07:47:44 GMT
>
> b
> Hello world
>
> 09:47:44.380398 IP (tos 0x0, ttl 64, id 52626, offset 0, flags [DF],
proto TCP (6), length 40)
>     127.0.0.1.44078 > 127.0.0.1.8080: Flags [R], cksum 0xd571 (correct),
seq 3052296895, win 0, length 0
> E..(..@.@.o;..............Z.....P....q..
>
> This shows the python "client", sends a FIN to tomcat, tomcat PUSH anyway
and then the "client" RESETs.
>
> Thomas
>
> 2016-10-10 19:10 GMT+02:00 Mark Thomas <markt@apache.org>:
>>
>> On 10/10/2016 15:47, Thomas Boniface wrote:
>> > Hello,
>> >
>> > I have managed to test this use case on the server revealing the issue
with
>> > the latest tomcat release (7.0.72). I still can observe the issue on
>> > catalina.out side: a broken pipe exception pops up and a recycle is
shown
>> > for the async context but no complete.
>>
>> Steps to reproduce?
>>
>> Better still, a test case that demonstrates the issue?
>>
>> Mark
>>
>>
>> >
>> > Oct 10, 2016 4:41:07 PM org.apache.coyote.AbstractProcessor
setErrorState
>> > INFO: An error occurred in processing while on a non-container thread.
The
>> > connection will be closed immediately
>> > java.net.SocketException: Broken pipe
>> >     at java.net.SocketOutputStream.$$YJP$$socketWrite0(Native Method)
>> >     at
java.net.SocketOutputStream.socketWrite0(SocketOutputStream.java)
>> >     at
java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
>> >     at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
>> >     at
>> >
org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215)
>> >     at
org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480)
>> >     at
>> >
org.apache.coyote.http11.InternalOutputBuffer.endRequest(InternalOutputBuffer.java:159)
>> >     at
>> >
org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:761)
>> >     at org.apache.coyote.Response.action(Response.java:174)
>> >     at org.apache.coyote.Response.finish(Response.java:274)
>> >     at
>> > org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:322)
>> >     at
>> >
org.apache.catalina.connector.CoyoteOutputStream.close(CoyoteOutputStream.java:108)
>> > ...
>> > Oct 10, 2016 4:41:07 PM org.apache.catalina.core.AsyncContextImpl
logDebug
>> > FINE: Req: 2de85b25  CReq: 70e2c044  RP: 1dff11c5  Stage: 7  Thread:
>> > http-bio-8080-exec-8  State:                  N/A  Method: recycle
>> > URI:
>> >
/www/delivery/swfIndex.php?reqType=AdsSetup&protocolVersion=2.0&zoneId=5335
>> >
>> > On application logs side the behavior changed a bit as I now have a
>> > IllegalStateException:
>> >
>> > java.lang.IllegalStateException: It is illegal to call this method if
the
>> > current request is not in asynchronous mode (i.e. isAsyncStarted()
returns
>> > false)
>> >     at
>> >
org.apache.catalina.connector.Request.getAsyncContext(Request.java:1740)
>> > ~[catalina.jar:7.0.72]
>> >
>> > In the end, the situation seems pretty similar. The container appears
to
>> > recycle the request without completing the async context and I can't
>> > complete on application side as the request I have is now recycled.
>> >
>> > Thanks,
>> > Thomas
>> >
>> >
>> > 2016-10-03 17:06 GMT+02:00 Thomas Boniface <thomas@stickyads.tv>:
>> >
>> >> Hi,
>> >>
>> >> Thanks for your feedbacks. I noticed the issue I described do not
occur on
>> >> my local or integration environment. I still try to figure out how to
>> >> reproduce this in an environment I can easely update to the latest
tomcat
>> >> version.
>> >>
>> >> Although it may not occur in latest release. Could you give me an
input on
>> >> what are the consequences of the behaviour I described ?
>> >>
>> >> Thanks,
>> >> Thomas
>> >>
>> >> 2016-09-29 9:41 GMT+02:00 Violeta Georgieva <violetagg@apache.org>:
>> >>
>> >>> Hi,
>> >>>
>> >>> 2016-09-29 10:14 GMT+03:00 Thomas Boniface <thomas@stickyads.tv>:
>> >>>>
>> >>>> The tomcat version is 7.0.64.
>> >>>
>> >>> I would recommend you to verify the behaviour against the latest
Tomcat 7
>> >>> (7.0.72).
>> >>> We have changes in the async processing since 7.0.64.
>> >>> http://tomcat.apache.org/tomcat-7.0-doc/changelog.html
>> >>>
>> >>> Regards,
>> >>> Violeta
>> >>>
>> >>>> Thomas
>> >>>>
>> >>>> 2016-09-28 22:43 GMT+02:00 Christopher Schultz <
>> >>> chris@christopherschultz.net
>> >>>>> :
>> >>>>
>> > Thomas,
>> >
>> > On 9/28/16 11:55 AM, Thomas Boniface wrote:
>> >>>>>>> Hi,
>> >>>>>>>
>> >>>>>>> When a client calls an asynchronous servlet and closes
the
>> >>>>>>> connection a java.io.IOException: Broken pipe is catched
by
Tomcat
>> >>>>>>> level when the webapp tries to write to the socket.
>> >>>>>>>
>> >>>>>>> This exception is not transmited to the webapp level
but it seems
>> >>>>>>> the request has been recycled (all content is reinitialised),
in
>> >>>>>>> such a case it impossible for the webapp to retrieve
the
>> >>>>>>> AsyncContext from the HttpServletRequest making the
AsyncContext
>> >>>>>>> complete call impossible.
>> >>>>>>>
>> >>>>>>> Activating the tomcat logging for AsyncContext
>> >>>>>>> (org.apache.catalina.core.AsyncContextImpl.level = FINE)
shows
the
>> >>>>>>> recycle method is called but not the complete method,
what seems
to
>> >>>>>>> confirm my assumption. In a use case were the client
waits for
the
>> >>>>>>> response, I can see both complete and recycle are called.
>> >>>>>>>
>> >>>>>>> My question is, what is the impact of the complete not
being
called
>> >>>>>>> on the AsyncContext, is the socket cleaned up properly
?
>> >
>> > Tomcat version?
>> >
>> > -chris
>> >>>>>
>> >>>>>
---------------------------------------------------------------------
>> >>>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> >>>>> For additional commands, e-mail: users-help@tomcat.apache.org
>> >>>>>
>> >>>>>
>> >>>
>> >>
>> >>
>> >
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>>
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message