On Thu, 9 Jul 2020 at 02:18, Brad Wood <bdw429s(a)gmail.com> wrote:
Thanks for the reply Stuart. That's a lot to take in so I'll
need to
digest it a bit. Is there any documentation for Undertow that dives into
that? I'm so used to completely synchronous execution once an HTTP request
has made it past the HTTP/AJP listener and into the servlet container, so
it's hard to wrap my head around some of the async stuff.
Just the stuff you have read. Conceptually there are a few key concepts:
- The exchange can end at any point
- Just because the call stack returns it does not mean the request is
ending, it might be about to perform async work (or it might be complete).
If you are doing anything on the way out of the handler chain (after
dispatching to the next handler) this is almost always something that
should have been done in a listener on the way in.
- Exchange .isComplete() and isDispatched() can be used to determine the
current state of the exchange
- Handler chains can be executed many times. Servlet requests will usually
have two, but async Servlet can have more, and if you do async Servlet it
may have multiple servlet dispatches.
Are you adding the listener before dispatching to the next handler or
> afterwards?
>
I think you're onto something there. The handler where I was previously
adding my exchange complete listener was "inside" of the predicates,
meaning it was never reached if a predicate ended the exchange meaning the
listener itself was never added. I moved it to another handler that wraps
the predicates and I can confirm that even if the response-code handler
ends the exchange, the exchangeCompleteListener does fire for the request.
Thanks for catching that-- I should have realized my order was backwards.
Mixing async and blocking is really hard, having something that can do both
efficiently is by far the hardest part of Undertow.
Stuart
Thanks!
~Brad
*Developer Advocate*
*Ortus Solutions, Corp *
E-mail: brad(a)coldbox.org
ColdBox Platform:
http://www.coldbox.org
Blog:
http://www.codersrevolution.com
On Wed, Jul 8, 2020 at 6:27 AM Stuart Douglas <sdouglas(a)redhat.com> wrote:
>
>
> On Tue, 7 Jul 2020 at 06:32, Brad Wood <bdw429s(a)gmail.com> wrote:
>
>> I hate asking generic questions, but I'm looking for a little
>> understanding or clarification on request lifecycles. If you haven't
>> noticed, I've had several recent threads that touch on this. Before anyone
>> asks,
>>
>> - Yes, I have read all the docs I can find on this Ex
>>
>>
http://undertow.io/undertow-docs/undertow-docs-2.0.0/undertow-request-lif...
>>
>>
http://undertow.io/undertow-docs/undertow-docs-2.0.0/#listeners-2
>>
>>
http://undertow.io/undertow-docs/undertow-docs-2.0.0/servlet-using-non-bl...
>>
>> - Yes, I have Google and read 3rd party docs and guides on Undertow.
>> Ex:
>>
>>
https://www.oreilly.com/library/view/jboss-developers-guide/9781788296199...
>>
>> - Yes, I have spent hours reviewing the code and experimenting
>>
>> I've learned a lot, but there's a couple elusive things that all the
>> docs and guides I see don't quite seem to satisfactorily explain for me.
>>
>> I'm trying to get some clarification on exactly what part of the request
>> happens inside the xnio worker thread and which part runs inside the
>> ThreadPoolExecutor. My server bootstrap wraps a number of various
>> HttpHandlers around the handler that I set into the server builder and I
>> had originally assumed that those handlers were part of the same handler
>> chain that invoked the servlet. This appears to not be the case. The
>> handler chain I pass to the server builder appears to execute as part of
>> the org.xnio.nio.WorkerThread.run() thread, while my servlet code executes
>> inside a thread pool executor.
>>
>> Both stack traces show that there is a chain of handler.handleRequest()
>> calls, but this duality causes some confusion and troubles for me. It also
>> seems to explain to an extent why Stuart's previous messages treated the
>> "servlet" as a concept so far removed from the initial handler chain.
>>
>> Even docs like the last link I provided above that contain this image...
>> [image: image.png]
>>
>> make it sound like there is a single "root handler". However,
>> *executeRootHandler* appears in the stack traces of both the XNIO
>> worker as well as during the servlet chain in the thread pool executor.
>>
>> at
>>>
io.undertow.server.handlers.SSLHeaderHandler.handleRequest(SSLHeaderHandler.java:105)
>>> *at
>>> io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)*
>>> at
>>>
io.undertow.server.protocol.http.HttpReadListener.handleEventWithNoRunningRequest(HttpReadListener.java:255)
>>
>>
>> at
>>>
io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
>>> *at
>>> io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)*
>>> at
>>> io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
>>
>>
>> This has proved to create difficulty in trying to
>> accomplish seemingly very simple tasks with Undertow. For example, an
>> example I gave in a previous thread was a simple task of logging every HTTP
>> request that returned a non-successful status code. Seems easy enough,
>> right? However...
>>
>> - I can't use an exchange complete listener because it doesn't fire
>> with handlers like *response-code* that end the exchange
>>
>>
> If you add the listener before the response code then it will work fine.
> Basically if you want to look at the result of a request you should do it
> in a listener, and you should add the listener as early as possible.
>
>
>>
>> - I can't wrap the servlet handler chain because that chain is never
>> invoked if the exchange is ended first by my predicates
>> - I can't wrap the handler chain being run in the XNIO listener
>> because it doesn't wrap the servlet chain so my "before" and
"after" code
>> all runs before the servlet chain starts.
>>
>> I would love any help and insight both on my general question for
>> documentation regarding the two separate handler chains as well as my more
>> specific question above about implementing something as simple as a
>> handler/listener that always runs at the end of an exchange.
>>
>>
> You can actually have more than 2, you can have any number, as Servlet
> requests can go async and then get re-dispatched back, and you can do
> similar things in core Undertow as well (e.g. BufferedRequestHandler will
> read the full request using buffered IO, which may cause the stack to
> return and then start again in the IO thread once all data has been read).
> If you want to act at certain points in the request you need to do it in a
> listener.
>
> With regard to listeners not being fired after the exchange has ended
> generally once the exchange has ended nothing else is exected to happen, so
> it seems a bit odd that you are still doing processing. Are you adding the
> listener before dispatching to the next handler or afterwards?
>
> Stuart
>
>
>> Thanks!
>>
>> ~Brad
>>
>> *Developer Advocate*
>> *Ortus Solutions, Corp *
>>
>> E-mail: brad(a)coldbox.org
>> ColdBox Platform:
http://www.coldbox.org
>> Blog:
http://www.codersrevolution.com
>>
>> _______________________________________________
>> undertow-dev mailing list
>> undertow-dev(a)lists.jboss.org
>>
https://lists.jboss.org/mailman/listinfo/undertow-dev
>
>