-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support for async action beans #37
Comments
That would be really nice! |
+1 On this feature |
+1 |
Hiya, I have committed a first draft of Async Stripes. Feedback most appreciated. The idea is to allow ActionBean implementor to return instances of When an action's event handler returns AsyncResolution, then Stripes triggers the async mode (via Here's an example of such an action, that uses a non-blocking http client to fetch data from a remote service, and completes the request via a callback : I had to change the lifecycle a bit (only for async : sync actions should be impacted), and to implement new interface methods here and there (like layouts etc) in order to support servlet 3. Also, there ain't no support for async stuff in MockRoundtrip at the moment. I have pushed a version to maven central so that you don't have to recompile for testing :
It's pushed in branch Please let me know if you have bugs, or see anything suspicious. |
Hi, Remi, It' a interesting move going to Servlet 3.0. I checked out your @async
|
Hi, Spring's @async is something totally different : it's meant to have component methods execute in a separate thread (with an executor), and has nothing to do with Servlet 3 AFAIK. Plus you'd have to return a Spring uses I prefer the base class. It's simple, easy, and effective. Plus I fail to see how you get access to the AsyncContext with the annotation (and even with the Callable approach)... Cheers Rémi |
Problem with tomcat7 :
Seems related to DMF. Because it creates an "internal" instance of the |
Hi Remi, my proposal of an @async annotation is independent from Spring. Normally we have action methods that returns a Resolution, something like public Resolution someWork() { As you can see the hard work is encapsulated in the method, this could be The process could be like this:
Your example could be really simplified: You won't need any //When the action method is @async annotated, the method is executed in Here link showing ExecutorService in action: http://www.javacodegeeks.com/2013/08/async-servlet-feature-of-servlet-3.html 2015-12-24 4:40 GMT-05:00 Remi Vankeisbelck [email protected]:
|
I like the idea of reusing ForwardResolution etc. I fully agree that the current impl is a draft and lacks higher level API for complete/dispatch. I was thinking of helper methods on the base AsyncResolution class. But it would be nicer to be able to reuse existing Resolutions if possible and meaningful. Otoh, the ExecutorService and non-blocking http client is a completely different matter. In my sample you precisely don't want another thread pool... What you want is to avoid blocking the appserver's threads while performing I/O operations... You cannot do this with a blocking client in an executor service : you'd end up starving this pool instead of the AS's. One should not confuse long-running operations with non blocking I/O. Those are 2 completely different things.
|
…cutorService needed. Async resolutions are handled as if blocking from trip.execute(). Behavior should be transparent for the test (sync or async, it should block)
Ok, I have a better version now, with MockRoundtrip working (ie you can unit test async actions...). @iluvtr I've thought about your comments on reusing Resolutions, and I think you are right. Dispatch, for example, is an easy one : it could reuse the Stripes APIs like you describe in ForwardResolution. My main concern is to know if it applies to all kinds of resolutions. Async writes can be different of regular, sync writes, so we could have incompatibilities there. I'm gonna continue digging... I'm still not sold on the annotation though. I think we need a callback mechanism, which will probably be pretty clumsy with an annotation. So if we can reuse the base For example, this regular, blocking event method :
Could become asynchronous by writing it like this :
Stripes could then detect async event handlers by looking at the method signature (it already does), and find the callback param. It would then use the code that currently checks if the returned Resolution is an async one or not. I think it's better than the current |
Hi Remi, your current way is much better. It reminds me JAXRS' Cheers.
|
Yep it's the regular "callback" approach, I also think it's better. The ActionBeanContext arg is optional in Stripes event handlers : you may declare it or not.
Unfortunately it's harder to implement against the current codebase... Requires some pretty heavy surgery in DispatcherHelper/Servlet : they were designed for synchronous event handlers. Patching Resolution subclasses should be OK but a good portion of the dispatch code needs to be refactored. @rgrashel : I thought about this : is the REST code needed in "core" dispatcher ? can't this be handled via interceptors (and therefore be less intrusive) ? |
Remi, I think we should think a better name instead of 'Consumer' because
|
It's the one from Java8 I'm talking about :) |
No need for another @FunctionalInterface here |
Oh, Stripes currently is supporting Java >= 5. I think it's a bold move to
|
Java7 was eol-ed last year. I'd say we go for Java8 directly... Any objection ? |
The reason I couldn't use interceptors for REST action beans is because of That's not to criticize interceptors or dispatching, but it would have been If we were doing it "right", I think the best move would be to make the -- Rick
|
@rgrashel thanks for the explanation. And I totally agree with you about the design of interceptors and the whole dispatch chain. I also fully agree with the re-write of the whole thing. I've faced issues that I had to workaround because of the current design. It's also a "problem" for the async thing. If we manage to go Servlet3 and have async, I think it's good enough for the upcoming major release. We have to see for Java 8. I'm using it but it's no blocker, I can rewrite in Java7 (or even 5 maybe). It's a group decision... |
…or reuse of Resolution classes. As the name says, completes the async processing. You cannot use several Resolutions when async processing.
I've been working on upgrading a Stripes, jax-ws based client to be async. I was wondering what would be the best way to 'abandon' an ActionBean that no longer needs to return a Resolution. I understand that the solution this thread is talking about will be better, but I've a short term need to make a web service call from Stripes async as soon as possible. Does Stripes have servlet.destroy() ? I know it's crude, but what about throwing some sort of exception as an option? |
I know a lot of people just implement Resolution their own and create a public class NullResolution implements Resolution { Or something like that. So create a null resolution and return that at the -- Rick On Thu, Jan 21, 2016 at 1:45 PM, roncking [email protected] wrote:
|
Thanks! That should solve my problem. On Thu, Jan 21, 2016 at 2:18 PM, Rick Grashel [email protected]
|
I don't really understand how this could work... If you use an asynchronous client, by definition, the Stripes event handler will end before your client has done its job. So this means that you will not be able to use the response of the webservice you are invoking from the action bean, you'll always return the same Resolution, no matter what. |
@roncking I'm afraid you'll have to wait for the async feature if you really want to use an async client in an efficient manner (ie using callbacks). Otherwise, you need to block yourself with your async client. This is usually done by calling |
Ok, I have made some progress. It's not final, but it's getting better. I'm still using the For example :
There's still lots of boilerplate. I'm trying to find a way to make this better (the I also have modified Feedback / review most appreciated. |
Here's what I'm doing, and it's not quite working. When the user presses Should I be trying something different? Is this something that I should be On Sat, Jan 23, 2016 at 7:00 AM, Remi Vankeisbelck <[email protected]
|
This sort of gets into what your application needs to do and the If this is a transaction of some sort, then it sounds like this needs to be Based on your post, it sounds to me like what you need is an asynchronous -- Rick On Sat, Jan 23, 2016 at 7:54 AM, roncking [email protected] wrote:
|
The Stripes application is communicating with a web service that I don't have much control over, and I think what you're describing that's doing the polling is the web service, correct? I don't need 100% durability, 99% is fine ;-) Can you tell me how to get the Writer output to be flushed to the web browser instantly? If I get that working, I think I have a workable solution by using email to send the transaction status to the user. |
What application server are you using? On Sat, Jan 23, 2016 at 8:54 AM, roncking [email protected] wrote:
|
I think Rick is right. You need a background scheduler, and probably polling, but this has nothing to do with non-blocking controllers, which is the subject of this ticket. @roncking Do you have access to the Mailing List ? We can help you with your problem there, we all have done this I guess (spawning long running tasks in the background). I'd prefer not to "pollute" this ticket, as it's not the topic. You can also open another issue in github. |
I'm using Tomcat 8. I'm sorry that I polluted this thread, how do I find the Stripes mailing On Sat, Jan 23, 2016 at 9:06 AM, Remi Vankeisbelck <[email protected]
|
Ok, I've refactored to something much better I think.
Of course, it's meant to be used with callback-based APIs, or in separate threads. Simplistic example :
As you can see, the The method signature tells Stripes it's async because :
When Stripes encounters such an "async handler", it starts an asynchronous cycle on the http request for you, and handles cleanup etc. Only event handling can be async : binding, interceptors are still synchronous. |
…AsyncResolution). AsyncResolution is no more a base class to extend but instead it's a param to the event handler that allows to complete() the async processing.
Hi folks, I have refactored some stuff in order to cut the runtime dependency on Servlet3 APIs. Stripes continues to run as usual on Servlet2+ containers (ie it still runs in old tomcat6 etc). Async events can be used in any Servlet3+ container (tomcat7+, jetty8+, etc.). I've also added profiles to the pom, in order to ease integration testing : they allow to run the tests on jetty92, tomcat7 and tomcat6.
The async webtest fails on tomcat6, which is expected. The tests also show a bug with tomcat7 (mentioned above in this thread), which we need to fix before we can "ship" the feature. The API should be stable, so I think it's time for more testing. So, if you want to help, please try the Async events in you app(s). An easy way to test is to "morph" some of your actual event handlers so that they do the same thing than before, but in "asynchronous style" :
becomes :
Even if it does nothing fancy, it'll use all the async dispatch code and will help spotting bugs, if any. We now need more testing, and feedback. Async actions heavily rely on container internals, and therefore the most containers we test, the better. I haven't published anything to maven central yet, so please checkout the |
Hi Remi, The name 'AsyncResolution' is a bit confusing because its purpose 2016-01-27 8:52 GMT-05:00 Remi Vankeisbelck [email protected]:
|
Agreed, bad naming. I like AsyncResponse. I'm refactoring this right now. |
I've been looking at the AsyncActionBean.java example. I honestly think we should push this entire asychronous execution logic into the dispatcher. In the AsyncActionBean example, all it ultimately does it return a resolution. The only differentiator between this and any other event handler is that the desire is for the event to run asychronously. An annotation could solve this nicely. For example, the event in AsyncActionBean.java could be written as:
This method could just as easily return a streaming resolution of JSON or any kind of other resolution. I also think doing this using an annotation would be much more in line with how this is done in JEE containers. I'm not in the middle of this, so I definitely might be missing something. |
@rgrashel An annotation doesn't do the job. You need to pass a callback arg. The whole point of non blocking actions is that you leave the request thread when starting an async cycle. For example, assume you launch a background task (submit a Runnable to a pool) from the action and want to complete() at the end ?
See ? Has to be a callback. The example AsyncActionBean cannot be written without a callback either : the http client works with callbacks, so you cannot return anything from the event method. You have to call complete(), that's how non blocking stuff works. Servlet3 provides the AsyncContext object for that. The |
closed by mistake ! |
Ok, after looking at the code and writing a prototype, I can see the issue now. There are actually two use-cases here: Use-Case 1) Dispatch a request asynchronously which has an event-handler that uses non-asynchronous code inside of it. Use-Case 2) Dispatch a request asynchronously which has an event-handler that uses asynchronous-code inside of it. With Use-Case 1, the dispatcher knows when to complete the AsyncContext because the event-handler returns a Resolution after the work is completed. In Use-Case 2, the dispatcher does NOT know when to complete the AsyncContext because the Resolution itself does not know when the asynchronous code inside of it has completed. This is the classic situation where some people kick of threads, and then yet more threads within those threads. So the design approach is that worker threads need to notify the monitor threads when they are complete and then the monitor threads need to notify the application so that it can return the results. Not my personal preference with how to design a system, but I understand that people can and may do this. The issue I see here is that if people only have Use-Case 1... they are being forced to write code as if they have Use-Case 2. In the example AsyncActionBean, I'd simply have made a blocking HttpClient call because the Resolution itself is already running asynchronously in a different thread pool and therefore is not blocking any request threads. For Use-Case 2, if you decide to write your already asynchronous method with asynchronous code inside of it, then you have to tell whatever started you that you are complete. But Use-Case 1 should not have to do this, IMHO. So as the current enhancement stands, I see it satisfying developers who write asynchronous code according to Use-Case 2. But I see it placing an unnecessary burden on developers who have Use-Case 1 and force them to write code in a way that they don't need to. It makes their code unnecessarily ugly, complex, and difficult to debug. If we want a complete and elegant solution, I think we should satisfy Use-Case 1... which is that the dispatching is done asynchronously if an event handler is defined as being asynchronous... and the event handler method can be written exactly as a normal event handler would be written within Stripes. |
I agree, there is 2 categories of "async servlet usage". Use case 1/ is about submitting tasks to another thread pool, and 2/ is the "real" non blocking, callback based approach. Both are valid, and used in different situations. But as you said, the proposed API solves the 2 use cases already : Use case 1/ :
Use case 2/ :
So, if I understand, you'd like to "hide" the AsyncResponse for use case 1/. Something like this is definitely doable (that's how they do it with Spring btw) :
Or
(I think the one with an annot is way more Stripey btw) But, to be honest I'm not sure it is unnecessary. Again, the two use cases are covered easily with the current code, so I nee no reason to have several ways to do it. I'd rather think it's better to have a single path and not several ones when it comes to using a framework in general. Also, I think async actions require to understand what asynchronism really means in this context. The On the other hand, I agree that it's unnecessary clutter to call complete() yourself in use case 1. I'm logging in on IRC right now :P |
In some cases (e.g. ActionBean calling webservice(s) or async messaging), we'd like to use the Servlet3 async feature, that allows for better performance (non-blocking).
Stripes could provide some plumbing in order to make it simple, and integrated with the rest of the framework.
The text was updated successfully, but these errors were encountered: