Skip to main content

New Asynchronous Servlet Transport in JAX-WS RI

Posted by ramapulavarthi on August 18, 2010 at 1:53 PM PDT

As you know, JAX-WS RI  has long supported publishing of asynchronous web services through the use of  RI specific AsyncProvider api. There have been requests to add the asynchronous support for the SEI based web services (the more common developer paradigm) and standardize it, I hope it would have a place in the future revision of the JAX-WS Spec. But the current AsyncProvider api can serve the purpose for advanced use cases with more control over the SOAP messages. Though this is an important ingredient for making the web services asynchronous, its usefulness could be leveraged only with the support of the underlying transport/communication framework. As Kohsuke mentioned in his blog, JBI has implemented a custom HTTP binding component over Grizzly that has capability to process requests in asynchronous manner.  But, like most other web frameworks, normal JAX-WS web service endpoints are published as servlets running in the web container. The SOAP messages get processed by the jax-ws runtime via servlet request/response. Until servlet 2.5, the servlet request processing is synchronous, i.e if the web service (underlying servlet) is waiting for a resource or event to happen, a container thread has to wait until the request is processed and response is committed. This would result into wasting precious container resources while the thread is blocked. This would be more apparent when you have thousands of concurrent requests to long running/slow running operations, where each thread servicing the request is blocked . Though the jax-ws runtime is capable of  asynchronous processing of requests,  it is limited by the blocking invocation model of the underlying servlet.

It's no longer the case as JAX-WS 2.2.2 RI makes use of the asynchronous servlet capabilities introduced in Servlet 3.0. With async programming model, the container thread is relinquished while the request is processed asynchronously, and when processing is done or a timeout occurs, the response can be sent or the request can dispatched back to the container. To make this happen, first the servlet needs to be declared as async-supported in web.xml or through @WebServlet annotation. For more details on asynchronous servlet programming model, refer to this techtip. JAX-WS runtime takes advantage of this asynchronous servlet layer( a transport layer interns of jax-ws) and the already existing AsyncProvider API to provide better scalability and efficient use of server resources. 

This asynchronous servlet transport feature is introduced in Glassfish V3.1 MS3 and you can find a working "asyncservice" sample in latest JAX-WS RI 2.2.2 nightly build or latest Metro 2.1 promoted build to try on any Servlet 3.0 supported container. I added a "asyncservice" sample demonstrating the usage of this feature.A quick recap of the how web service implementation looks,

@WebServiceProvider
public class AsyncProviderImpl implements AsyncProvider<Source> {    
    public void invoke(Source source, AsyncProviderCallback cbak, WebServiceContext ctxt) {
        ...
        //queue the request for long running operation
        queueRequest(source,cbak,ctxt);
        //return, response is sent via cbak.send(response) or cbak.sendError(throwable) in a separate thread
    }
}
Here, the request is queued or processed in a separate thread releasing the container thread. The response is sent by calling the AsyncProviderCallback.send(response) or AsyncProviderCallback.sendError(throwable). As a second step, to make it truly asynchronous with the servlet web service endpoints, you need to mark the JAXWSServlet as async capable by specifying  <async-supported> true</async-supported>. As I blogged earlier, web.xml configuration is optional now, in that case, JAX-WS by default registers the servlet as async supported. If the response is not sent in a expected time interval, timeout occurs and JAX-WS runtime sends an error response. Currently, the timeout for the web service relies on the servlet implementation default. In future, we may provide an explicit configuration for the timeout.

Though this feature helps in better scalability on the server-side, the HTTP connection is still open in the background and the client  might be still waiting for the response because HTTP is a request/response protocol. One could use the support of the other WS-* specifications like Non-anonymous Addressing feature for addressable clients or WS-MakeConnection for non-addressable clients to make it asynchronous end-to-end. I will write about doing that with Metro in a future blog.