Facebook BigPipe in an Async Servlet

July 14, 2010

Since Subbu wrote BigPipe using node.js, I had to see how the same thing would look like in a Java async servlet.

Stephan Schmidt had already written Facebook BigPipe for Java, but using a synchronous servlet model, not asynchronous. I decided to implement it using Jetty continuations and the Jetty HTTP client, but the code should be easy to adapt to servlet 3.0 AsyncContext.

The code initially constructs the page with a few empty divs that will contain the pagelets, for example:

<div id='pagelet3'></div>

I keep the connection open from the browser to the server while I render pagelets. As pagelets become available, I flush them onto the browser, which in turn inserts them into the right place in the DOM using Javascript. Assuming we get back a response from the remote module protocol:

<span>some useful message for module: pagelet3</span>

We wrap it inside Javascript so that it looks like:

<script>arrived('pagelet3', '<span>some useful message for module: pagelet3</span>');</script>

All is left is for the arrived function to update the pagelet3 element in the DOM. In terms of concurrency, the initial page construction is done synchronously. As soon as I have the frame in place with the divs that will eventually hold the pagelets, I suspend the execution of the servlet, which in turn releases the thread that was attached to the client connection. At that point, I fire in parallel HTTP client requests to the remote module server.

For resuming the continuation, I could have used a counter, but since each HTTP client execution is a separate thread, unlike in node.js, I did not want to have to acquire a lock and synchronize to be able to update the counter. Instead, I used request attributes, as setting, getting and removing them is thread safe. The code keeps a list of references to the elements that we are offloading to a remote module server, as an ArrayList with the ids to fire parallel requests to http://localhost:8080/module?id={id}; each id is also kept as a request attribute. As each request comes back from the remote module server, I write and flush the response buffer, so that the element appears on the browser immediately, and I remove the corresponding request attribute.

Although the code is not as readable and straight forward as what Subbu got with node.js, I am actually surprised how simple the async Java solution actually turned out to be.


blog comments powered by Disqus