[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
[jetty-dev] Unintuitive behavior of async context
|
Consider the following servlet emulating long-running output (>30s) via
Async context:
==============================================================================
public class AsyncCtxSnippet extends HttpServlet {
private static int workerCount = 0;
private static class Worker implements Runnable {
private AsyncContext ctx;
public Worker(AsyncContext ctx) {
this.ctx = ctx;
System.out.println("Creating worker " + (++workerCount));
}
@Override
public void run() {
try {
ServletOutputStream out =
ctx.getResponse().getOutputStream();
for (int i = 0; i < 40; i++) {
out.println("async " + i);
out.flush();
Thread.sleep(1000L);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
ctx.complete();
}
}
}
protected void doGet(
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
if (request.isAsyncStarted()) {
System.out.println("Already processing this - skip?");
} else {
System.out.println("Processing new request:" + request);
AsyncContext ctx = request.startAsync();
//ctx.setTimeout(0);
ctx.start(new Worker(ctx));
}
}
@Override
public void destroy() {
}
public static void main(String args[]) throws Exception {
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler(
server, "/", ServletContextHandler.SESSIONS);
context.addServlet(AsyncCtxSnippet.class, "/async");
server.start();
server.join();
}
}
==============================================================================
If I forget to set AsyncContext timeout (commented in the code) the
following will happen:
* Container will reenter doGet with the same request and response
objects with the isAsyncStarted() method returning false:
Processing new request:(GET /async)@18093747
org.eclipse.jetty.server.Request@11416b3
Using async context:org.eclipse.jetty.server.AsyncContextState@a456bb
Creating worker 1
Processing new request:(GET /async)@18093747
org.eclipse.jetty.server.Request@11416b3
Using async context:org.eclipse.jetty.server.AsyncContextState@a456bb
Creating worker 2
* On the client side both workers would write to the same stream:
...
async 30
async 0
async 31
async 1
async 32
async 2
async 33
async 3
async 34
async 4
...
until the first worker finishes and completes the context (which both
workers share) with the following exception.
I guess this timeout behavior is not specified in the Servlet API and
container is valid to do whatever it wants, but I think it breaks the
principle of least astonishment. I would maybe expect "closed" context
exception for the first (time-outed) worker with separate contexts, or
some other notification that something went wrong (and the AsyncContext
got time-outed), or maybe container would just give-up and not retry the
request at all. What do you think?
Where in documentation of Jetty this retry policy is specified?
Is the only way that I can find out about timeout is AsyncContext
listener? I haven't check but since the AsyncContext instance is the
same in both workers I might receive notification in both workers...
So novice programmers (which I am) writing async servlets with
long-running output would certainly face some unexpected behavior from
the Jetty container here. Any help from the container that programmer is
doing smth wrong would be priceless (maybe even warning in the log about
timeout and reentering servlet is enough?).
Regards,
Alexandr Ekushev