Bug 54928 - IllegalStateException: Calling [asyncError()] is not valid for a request with Async state [COMPLETING]
Summary: IllegalStateException: Calling [asyncError()] is not valid for a request with...
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 8
Classification: Unclassified
Component: Catalina (show other bugs)
Version: 8.0.x-trunk
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: ----
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-05-04 12:41 UTC by Rossen Stoyanchev
Modified: 2014-10-25 23:25 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rossen Stoyanchev 2013-05-04 12:41:30 UTC
In an async scenario (request.startAsync), when the client goes away, trying to write to the response raises an IOException. If I then call asyncContext.complete() in order to finalize and clean up the request, soon after the following exception occurs:

java.lang.IllegalStateException: Calling [asyncError()] is not valid for a request with Async state [COMPLETING]
        at org.apache.coyote.AsyncStateMachine.asyncError(AsyncStateMachine.java:304)
        at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:793)
        at org.apache.coyote.Request.action(Request.java:373)
        at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:441)
        at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:312)
        at org.apache.coyote.http11.AbstractHttp11Processor.asyncDispatch(AbstractHttp11Processor.java:1509)
        at org.apache.coyote.http11.Http11NioProcessor.asyncDispatch(Http11NioProcessor.java:221)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:619)
        at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1581)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1540)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
        at java.lang.Thread.run(Thread.java:722)

It looks like an attempt to maybe to send an error event to AsyncListener's but asyncContext.complete has already been called.

Is calling asyncContext.complete() a reasonable way to handle an IOException from the response in order to finalize the request and release any resorces associated with it?
Comment 1 Mark Thomas 2013-05-04 17:43:11 UTC
This is a question for the users list if you want to discuss this further (and possibly the Servlet EG as I don't see a clear definition of how an app is expected to handle this in the spec).

I'm assuming that the I/O operation that triggers the error does not occur on a container thread. If it occurs in a container thread let Tomcat handle it.

Looking at the Tomcat source code, a dispatch to a simple error page should trigger an error when it tries to write to the response which in turn should trigger the onError method of any registered AsyncListener allowing you to do the clean-up.
Comment 2 Rossen Stoyanchev 2013-05-04 19:18:55 UTC
Okay, I see. It looks like one has to dispatch before calling asyncContext.complete(). I opened this ticket because of the exception but I didn't realize it was illegal ot call complete() from a non-container thread. Maybe that can be detected and rejected with a message to that extent.
Comment 3 Mark Thomas 2013-05-04 19:39:19 UTC
(In reply to comment #2)
> Okay, I see. It looks like one has to dispatch before calling
> asyncContext.complete().

In this case you need the dispatch to get the request back onto a container thread where the error handling can deal with the error. It is this bit I am not 100% is what is intended by the spec but I can't find any clear definitions.

> I opened this ticket because of the exception but I
> didn't realize it was illegal ot call complete() from a non-container
> thread. Maybe that can be detected and rejected with a message to that
> extent.

It is perfectly valid to call complete() from a non-container thread.

Again, the users list is the place to discuss this.
Comment 4 Mark Thomas 2013-05-17 10:05:49 UTC
I've been pondering this and having thought about the question you asked on the Servlet spec users list, I have reached the conclusion that allowing complete() makes the most sense here.

I'm re-opening this to make this change for 7.0.41

The EG may ultimately come to a different conclusion. We'll deal with that if it happens.
Comment 5 Rossen Stoyanchev 2013-05-17 13:41:25 UTC
OK, thanks. For what it's worth, from brief experimentation calling complete() in this scenario on Jetty and Glassfish doesn't cause any exceptions. Not sure that means it works but if it doesn't it could be considered a bug since it completes silently.
Comment 6 Mark Thomas 2013-05-23 20:38:40 UTC
I think some other changes might have fixed this. Please can you re-test with the latest trunk.
Comment 7 Rossen Stoyanchev 2013-05-23 23:30:10 UTC
I can confirm the exception no longer appears in the logs. Thanks for fixing this!
Comment 8 Konstantin Kolinko 2014-10-25 23:25:36 UTC
(In reply to comment #4)
> I'm re-opening this to make this change for 7.0.41

I backported the test case to Tomcat 7 in r1634259. The test case passes successfully.