Dienstag, 27. November 2012

Realizing async server architecture with GWTP and Atmosphere

We have been using the GWTP framework for several production applications so far. While the MVP module of GWTP allows for a maintainable and scalable client architecture, the GWTP-Dispatch module centralizes client-server communication around the command pattern with features like action handlers, caching and batching. 

Recently we have been working on integrating the Atmosphere framework and GWTP-Dispatch with the goal of allowing asynchronous execution of server code while maintaining the command pattern approach that GWTP-Dispatch uses. Specifically we had to work with some Camel endpoints and Akka actors that do some work and asynchronously provide a result which was to be displayed on the client.


Traditionally one would use polling to fetch the result later on but Atmosphere actually uses long polling - the request stays open until a response is written. Some servlet containers only have a very limited thread pool to handle requests, in these cases long running requests block the threads from handling other requests resulting in waits on the clients. With Atmosphere the thread that handles the request is suspended thus freeing the resources to handle other requests. To do that, Atmosphere uses different approaches depending on the servlet container that is being used, for example Servlet 3.0 with async support or Jetty Continuations. 

Now on to the implementation, Atmosphere already has an atmosphere-gwt-poll module that is based on the GWT RPC mechanism and provides a class called AtmospherePollService which is an implementation of the GWT RemoteServiceServlet class and can be used as base class for the GWTP DispatchService. It suspends the request and dispatches the actions to the fitting ActionHandlers. In contrast to the synchronous action handlers, the methods in the asynchronous implementation do not return a result, instead they receive a callback as parameter which expects the result of the action.

@Override
public void execute(final HeavyWork action, PollExecutionContext context, 
                    final PollCallback<HeavyWork, HeavyWorkResult> callback)
                      throws ActionException {
       
  // delegate the heavy work to a new thread
  new Thread() {
            
    @Override
    public void run() {
      final HeavyWorkResult result = new HeavyWorkResult();
                
      // calculate result
                
      callback.onSuccess(result);
    }
  }.start();
}

With the recent move of GWTP to Github it was easy to fork and provide the module together with an example on Github. It is currently based on Guice, we will however split it up into separate Spring and Guice modules over the next few days. There is also more work to be done regarding batch actions, batch action should be able to be executed in sequence or in parallel.

So why would it make sense to use this? Well if you have long running requests, maybe because of expensive computation or slow backends this will free up some resources and still allow you to send results back to the client. You can even split up your computation and use multiple processors, that would be very hard to do with a synchronous solution. Asynchronous execution may also be a first step towards a distributed and scalable service layer.


Comments and discussions are welcome!