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: Wed, 10 Jul 2019 15:23:48 +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

Hi,

There are a fair number of permutations and combinations to test here.
Even more once you add h2 and/or async IO into the mix which I haven't
done yet.

The factors my tests cover so far are:
- sync or async servlet
- error triggered by sendError or unhandled Exception

Further, for async servlet
- Use complete() or dispatch()
- Use AsyncContext.start(Runnable) or app provided Thread
- When to trigger the error
  - Thread A before startAsync
  - Thread A after startAsync, before Thread B is started
  - Thread A after startAsync, after Thread B is started
  - Thread B before complete()/dispatch()
  - Thread B after complete()/dispatch()

I've found one edge case we could handle better: Unhandled Exception on
Thread B started via AsyncContext.start(Runnable).

Generally, the understanding set out below is correct. I've added a few
comments.

<snip/>

>     On 09/07/2019 14:15, Greg Wilkins wrote:
<snip/>

>     > 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).

Correct.

>     > 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

noop glosses over some internal complexities but it is a reasonable
description from the apps point of view.

>     >   * 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?

Broadly the same behaviour as in a synchronous servlet if the app calls
sendError() and then continues writing to the response.

>     > What if it calls sendError and then times out?

The listener gets called which calls dispatch()/complete() and
processing continues as if the servlet made that call.

>     > 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.

An async dispatch seems closer to RequestDispatcher.include than
.forward but I see where you are coming from. The app gets an ISE but
does the container handler the original error or the ISE? I'd lean
towards the original error.

>     > 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?

I think so.

I am concerned that there are a LOT of moving parts here. Anything we
can do in the next iteration of the spec to clarify the expected
behaviour would be welcome.

Mark


Back to the top