Skip to main content

When is async-complete complete?

Posted by swchan2 on May 14, 2013 at 11:39 AM PDT

Update: In Servlet 3.0, the behavior of using response is undefined after invoking #complete or #dispatch. In Servlet 3.1, it is clarified that AsyncContext#getResponse will throw IllegalStateException. The blog has been updated for this.

Asynchronous operation is supported in Servlet 3.0. I have discussed startAsync in my previous blog, startAsync in Servlet 3.0. In this blog, I will discuss AsyncContext#complete. The javadoc of AsyncContext#complete has the following:

Completes the asynchronous operation that was started on the request that was used to initialize this AsyncContext, closing the response that was used to initialize this AsyncContext.
...
If this method is called before the container-initiated dispatch that called startAsync has returned to the container, then the call will not take effect (and any invocations of AsyncListener#onComplete(AsyncEvent) will be delayed) until after the container-initiated dispatch has returned to the container.

Is it "AB" or "BA"?

Let us take a look at the following example. What is the message logged here?

import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;

@WebServlet(urlPatterns={"/test"}, asyncSupported=true)
public class TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res)
            throws IOException, ServletException {

        final AsyncContext asyncContext = req.startAsync();
        asyncContext.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent event) throws IOException {
                 log("A");
            }

            @Override
            public void onTimeout(AsyncEvent event) throws IOException {
                 // do nothing
            }

            @Override
            public void onError(AsyncEvent event) throws IOException {
                 // do nothing
            }

            @Override
            public void onStartAsync(AsyncEvent event) throws IOException {
                // do nothing
            }
        });

        new Thread() {
            @Override
            public void run() {
                asyncContext.complete();
            }
        }.start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // ignore
        }
        log("B");
        res.getWriter().write("Done");
    }
}

The answer is "BA" even though there is a sleep of 5 seconds there.
In this case, the async-complete only take effects after leaving the HttpServlet#service method.

Asynchronous operation in Servlets is implemented in GlassFish. You can download the latest GlassFish 4.0 from here.