Hi, I have a question regarding async servlets and request recycling. In particular, I'm interested in request recycling by tomcat when an IO error occurs. In my use case, I'm using non-blocking reads with a ReadListener but blocking writes (no WriteListener).
The main question can be summarized as the following: Does tomcat always call the AsyncListener's onComplete method before recycling the request and response objects? I assumed that this must be true, but I have discovered that it is not so. My scenario very much resembles the one described in the following thread from 2016 except that the IO exception occurs on a container thread: http://mail-archives.apache.org/mod_mbox/tomcat-users/201611.mbox/%3c0d28a20f-fa3d-9e58-b5d7-82950ca51...@apache.org%3e Also, my scenario is extremely similar to the scenarios described in the following bug reports: https://bz.apache.org/bugzilla/show_bug.cgi?id=59219 https://bz.apache.org/bugzilla/show_bug.cgi?id=59220 Those bugs were mainly fixed by modifying the service method of the CoyoteAdapter class, but in my scenario, it looks like it's the asyncDispatch method that is being hit instead. Description of the scenario In a servlet, start async processing and register a read listener for non-blocking IO processing. In the read listener, perform blocking writes on the response when the onAllDataRead callback is called. Importantly, catch IOExceptions and don't let them bubble up. Also start a non-container thread that will access the request and/or response object some time in the future. This processing will be prevented if the AsyncListener's onComplete method is called. We can assume that this is properly synchronized. Have a client access this servlet, but immediately disconnect without waiting for the response. This will cause the write operations in the ReadListener's onAllDataRead method to throw IOExceptions, but as mentioned previously this exception is caught and silenced by the servlet. The AsyncContext complete method is also NOT called by the servlet at any time. Tomcat then processes the IO error and recycles the request and response objects. Some time later, the non-container thread attempts to access the request and/or response objects and gets hit with a non-checked exception because they have been recycled. This behavior has been observed in tomcat 8.0.53 and 9.0.24. I have not tested it on 9.0.30 yet. There are a few changes related to async processing since 9.0.24 but none of them seem related to that scenario. For the record, here they are (from the changelog): 63682: Fix a potential hang when using the asynchronous Servlet API to write the response body and the stream and/or connection window reaches 0 bytes in size. (markt) 63816 and 63817: Correctly handle I/O errors after asynchronous processing has been started but before the container thread that started asynchronous processing has completed processing the current request/response. (markt) Ensure that ServletRequest.isAsyncStarted() returns false once AsyncContext.complete() or AsyncContext.dispatch() has been called during AsyncListener.onTimeout() or AsyncListener.onError(). (markt) 63931: Improve timeout handling for asyncIO to ensure that blocking operations see a SocketTimeoutException if one occurs. (remm/markt) Please let me know if my understanding of the servlet API is wrong regarding asynchronous operation and non-blocking IO processing! I can adjust my servlet to do the appropriate cleanup when an IOException is caught, but it seems so much hackier and uglier than just processing an onComplete or onError callback. Regards, François --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org