Hi folks,
I've played a bit with Async Support.
I want to be able to use Servlet3's AsyncContext feature in order to write
non-blocking style Stripes actions.
My use case is asynchronous, non-blocking invocation of a remote Web
Service in an Action Bean's event handler, which gets the webservice
response and forwards to some view :
1/ the handler is invoked
2/ it uses an async http client in order to contact a web service, passing
it a callback
3/ callback is called when the web service returns
4/ action bean does some processing of the WS response
5/ view (JSP) is rendered
This is not possible with Stripes out of the box : the lifecycle is
implemented over the thread-per-request, synchronous model.
So I wondered how we could implement this, in a simple and non-disruptive
manner.
The simplest solution I found was to introduce a new Resolution abstract
subclass, called AsyncResolution. This one would get passed the
AsyncContext, and would do whatever it needs with it, with the
responsibility of completing or dispatching.
You can then write an asynchronous handler like this :
public Resolution myAsync() {
return new AsyncResolution() {
...
}
}
A full example that performs a request on the GitHub API :
https://github.com/StripesFramework/stripes/blob/remi_async/examples/src/main/java/net/sourceforge/stripes/examples/async/AsyncActionBean.java
(It's a very verbose example of course but shows how it's done)
The AsyncResolution is a Resolution and has an "execute(request,response)"
method. But it also has a reference to the AsyncContext that Stripes has
started for us : the dispatcher now checks whether the Resolution is async
or not, and starts async processing if needed, passing the AsyncContext to
the resolution.
Therefore, the resolution can access the AsyncContext in its
execute(req,resp) method, and call asyncContext.complete() or dispatch().
I had to change the lifecycle a little bit to make this work, and also to
cleanup some ThreadLocals that were never removed. The thread is basically
"lost" as soon as you call request.startAsync(), so the ExecutionContext
thread local leaked.
Also, this approach doesn't allow for async TypeConverters, Interceptors
etc. : we'd need to rewrite the whole lifecycle in order to make this work.
But I don't know if it's a mandatory requirement. The main requirement for
me is that I can leverage the non-blocking model when calling external web
services from my controllers.
What do you guys think ? Are you interested in this feature ? I think it's
a must have today, but maybe it's just me...
I have commited my code in a "remi_async" branch, if you want to try it
out. There's also an async action example, along with the other samples,
the one that fetches commits from gh asynchronously.
Cheers
Rémi
------------------------------------------------------------------------------
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development