Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [servlet-dev] Async sendError with error pages?
  • From: Mark Thomas <markt@xxxxxxxxxx>
  • Date: Tue, 9 Jul 2019 16:12:32 +0100
  • Autocrypt: addr=markt@xxxxxxxxxx; prefer-encrypt=mutual; keydata= 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
  • Delivered-to: servlet-dev@xxxxxxxxxxx
  • List-archive: <https://www.eclipse.org/mailman/private/servlet-dev>
  • List-help: <mailto:servlet-dev-request@eclipse.org?subject=help>
  • List-subscribe: <https://www.eclipse.org/mailman/listinfo/servlet-dev>, <mailto:servlet-dev-request@eclipse.org?subject=subscribe>
  • List-unsubscribe: <https://www.eclipse.org/mailman/options/servlet-dev>, <mailto:servlet-dev-request@eclipse.org?subject=unsubscribe>
  • Openpgp: preference=signencrypt
  • User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.7.2

On 09/07/2019 14:15, Greg Wilkins wrote:
> Mark, Stuart, et al,

Greg,

There are enough edge cases and moving parts here that I want to run
some tests to confirm exactly what happens in some cases. I'll update
this thread when I have some concrete information.

Another factor to bring in to this is the unhandled exception.

Mark


> 
> I think that jetty will change to follow the implementations of Tomcat
> and Undertow.   Which if I understand correctly is as follows for an
> non-async caller:
> 
>   * Thread A Normal REQUEST dispatch
>   * Thread A calls sendError (state changed, output closed, but response
>     not committed)
>   * Thread A returns from REQUEST dispatch
>   * Thread A output reopened, ERROR dispatch.
>   * Thread A generates error page (perhaps calling startAsync and an
>     extended lifecycle).
> 
> But we'd also like to handle async callers of sendError.   Do your
> containers handling it like this?:
> 
>   * Thread A Normal REQUEST dispatch
>   * Thread A calls startAsync
>   * Thread B calls sendError  (state changed, output closed, but
>     response not committed)
>   * Winner of race between Thread A returning from REQUEST dispatch and
>     Thread B calling complete() does noop
>   * Loser of race reopens output and does ERROR dispatch
>   * Thread A/B generates page (perhaps calling startAsync and an
>     extended lifecycle).
>   * Thread A/B calls onComplete when ERROR dispatch returns or second
>     async lifecycle completes.
> 
> I think that works for an async thread calling sendError then complete,
> but there are some edge cases that need to be considered.  What if it
> calls sendError and then AsyncContext.dispatch? What if it calls
> sendError and then times out?
> 
> I think that sendError followed by AsyncContext.dispatch should be
> handled with an ISE, just like trying to use a normal dispatcher would
> if sendError had been called.
> 
> I'm not sure at all what to do on the timeout.   If there is no
> onTimeout listener, then we'd do a ERROR dispatch for the timeout, so
> perhaps we do the same:
> 
>   * we call any onTimeout listeners, if they call dispatch, then it is
>     ISE. If they call complete then we have our complete call and
>     proceed as above.
>   * If there are no onTimeout listeners or if they don't call complete,
>     then we just do the ERROR dispatch for the sendError rather than for
>     the timeout?
> 
> 
> Thoughts?
> 
> 
> On Mon, 8 Jul 2019 at 04:42, Stuart Douglas <sdouglas@xxxxxxxxxx
> <mailto:sdouglas@xxxxxxxxxx>> wrote:
> 
> 
> 
>     On Sat, 6 Jul 2019 at 02:33, Mark Thomas <markt@xxxxxxxxxx
>     <mailto:markt@xxxxxxxxxx>> wrote:
> 
>         On 05/07/2019 10:28, Greg Wilkins wrote:
>         >
>         > All, as much fun as it is talking about name changes, I'd like
>         to have a
>         > discussion about the actual semantics of the API :)
> 
>         What? And make some real progress? It will never catch on.
> 
>         > We (jetty-project) are currently reviewing how we handle
>         sendError when
>         > invoked asynchronously with an error page mapping.    I'm not
>         sure we
>         > really have the right semantic in all situations for the
>         combinations of
>         > async caller and async error page.
> 
>         Are there use cases for async error pages? My expectation is
>         that error
>         pages would either be static or would maybe dynamically add some
>         error
>         information from the request.
> 
>         I'm not saying we shouldn't support async error pages but it
>         does seem
>         ... odd.
> 
>         Generally, Tomcat differs in that when sendError() is called it
>         sets an
>         error flag but waits until control has returned to the container to
>         dispatch to the appropriate error page. The expectation is that
>         the app
>         returns control immediately after calling sendError() but if it
>         doesn't
>         Tomcat just ignores anything the app tries to write after
>         sendError()
> 
>         More specific commentary in-line for each case.
> 
>         > *Non async caller with non async error page. *
>         > This is the normal case and the error page is invoked with and
>         ERROR
>         > dispatch from within the scope of the sendError call.  After
>         returning,
>         > the response is committed and we close the output, so no more
>         can be
>         > written.  The javadoc on says this should be considered:
>         >
>         >     * After using this method, the response should be considered
>         >     * to be committed and should not be written to.
>         >
>         > But jetty does enforce it (and I think the TCK tests for this).
> 
>         Tomcat enforces this and silently swallows any further attempts
>         to write
>         to the response. This restriction is lifted once the error handling
>         takes over so the error page can be written to the response.
> 
> 
>     Undertow is the same.
>      
> 
>         > *Non async caller with async error page.*
>         > Here sendError does and ERROR dispatch to the error page,
>         which then
>         > calls startAsync and returns.  Now sendError can't commit nor
>         close the
>         > response, because it is in a race with async threads that may
>         be writing
>         > the response.   So we use an isAsyncStarted check to avoid
>         > committing/closing... so I guess that explains why the javadoc
>         only says
>         > "considered to be ..."?
> 
>         Tomcat avoids this race because of when it performs the dispatch.
> 
> 
>     Undertow also does the same, when sendError is called the currently
>     running request return to the container before actually doing the
>     error dispatch. 
>      
> 
> 
>         > *Async caller with non-async error page.*
>         > A normally dispatched request has called startAsync and then
>         an async
>         > thread calls sendError.  Current releases of jetty do an ERROR
>         dispatch
>         > to the error page from within the scope of sendError, but we
>         now realise
>         > that is not correct because the original dispatched thread may
>         not yet
>         > have exited and we will end up with 1 threads inside the servlet
>         > container (and filters etc.) for the same request at the same
>         time.   
>         >
>         > So we are considering making the error page dispatch an
>         > AsyncContext.dispatch.   This solves the concurrency problem,
>         but gives
>         > us other problems.  Should the dispatch type now be ASYNC or
>         ERROR?
>         > There is no ASYNC_ERROR!     Should the calling thread call
>         > AsyncContext.complete()?  Typically it will because that is
>         the contract
>         > of async and the caller has no idea if an async dispatch is
>         done or not
>         > inside the sendError call?  So assuming they do call
>         complete(), should
>         > we just treat it like a noop rather than ISE ?
> 
>         I'd lean towards using ERROR.
> 
> 
>     +1
>      
> 
>         I think the calling thread should call complete().
> 
>         What is the dispatch target's justification for calling
>         complete()? That
>         seems wrong to me so an ISE looks reasonable.
> 
> 
>     I don't know if it is really in line with the spec but we just
>     implicitly call complete() here when the error dispatch is done. 
>      
> 
> 
>         > *Async caller with Async error page.
>         > *
>         > A normally dispatched request has called startAsync and then
>         an async
>         > thread calls sendError, which does an async (or error?)
>         dispatch to the
>         > error page that then calls startAsync again.
> 
>         That isn't legal is it? Tomcat would throw an ISE in that situation.
> 
> 
>     We would also throw an ISE.
>      
> 
> 
>         >  We now how two threads
>         > that are acting on the same async request.  Do we wait for
>         both to call
>         > complete() before being complete? Surely we have to prevent a
>         complete
>         > call from the sendError thread from completing the async cycle
>         of the
>         > error page startAsync?  What if one of them calls
>         > AsyncContext.dispatch?   At this point we are thinking that once a
>         > request goes async, then perhaps we should never dispatch to
>         an error
>         > page from sendError and instead just generate our own simple
>         error page?
>         >
>         > I'd love to know what the other containers do in these situations?
>         >
>         > I think we obviously need to at least be more specific in our
>         javadoc,
>         > but I'm thinking that perhaps we might need to change
>         behaviour as well
>         > to avoid async on async error pages?
> 
>         I think being more specific would be a good thing.
> 
>         Would stating that targets of ERROR dispatches must be synchronous a
>         possible way forward?
> 
> 
>     I don't really like this. My gut feeling is that that sendError
>     should work like javax.servlet.AsyncContext#dispatch, and basically
>     finish the current async cycle. If the error page wants to do its
>     own async processing then it can just call startAsync again.
> 
>     Stuart
>      
> 
> 
>         Mark
>         _______________________________________________
>         servlet-dev mailing list
>         servlet-dev@xxxxxxxxxxx <mailto:servlet-dev@xxxxxxxxxxx>
>         To change your delivery options, retrieve your password, or
>         unsubscribe from this list, visit
>         https://www.eclipse.org/mailman/listinfo/servlet-dev
> 
>     _______________________________________________
>     servlet-dev mailing list
>     servlet-dev@xxxxxxxxxxx <mailto:servlet-dev@xxxxxxxxxxx>
>     To change your delivery options, retrieve your password, or
>     unsubscribe from this list, visit
>     https://www.eclipse.org/mailman/listinfo/servlet-dev
> 
> 
> 
> -- 
> Greg Wilkins <gregw@xxxxxxxxxxx <mailto:gregw@xxxxxxxxxxx>> CTO
> http://webtide.com
> 
> _______________________________________________
> servlet-dev mailing list
> servlet-dev@xxxxxxxxxxx
> To change your delivery options, retrieve your password, or unsubscribe from this list, visit
> https://www.eclipse.org/mailman/listinfo/servlet-dev
> 



Back to the top