Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[jetty-users] problem with continuation reuse - how to sync timeout with async task?

I'm using jetty-8 (embedded) and have a servlet that upon request starts some (lengthy) computation in the background and wants to return this to the user after completion. I try to use the https://wiki.eclipse.org/Jetty/Feature/Continuations#Suspend_Continue_Pattern (even though the problem will exits also with suspend/resume). The problem occurs when I set a timeout (I just want the task to wait a certian amaount of time for completion and cancel it then):

If the continuation times out I send an error back to the client (see code below), but my async task still holds a reference to the continuation. Since jetty reuses the continuation object after timeout, when the task now finished and tries to contine the continuation I get problems since
  a) The continuation is reused but for a completely different request
  b) The continuation is reused but not reasigend yet

This mainly leads to weird exceptions and since the continuation is reused I even can't avoid them by query continuation state.

Is there any option/workaround to circumvent this or diable continuation recycling? Or must all access to the continuation be syncronized in some way? I attached the basic code I use in the servlet and two of the exceptions I see, note that normally all works fine, just in high load where timouts occur there is where the problem arises.


Code:
final Continuation continuation = ContinuationSupport.getContinuation(req);
 if (continuation.isExpired()) {
   // Timout, provider has taken too long to succeed
   if (!resp.isCommitted()) {
      resp.addIntHeader("Retry-After", WORKER_TIMEOUT * 2);
      resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
   }
   return;
 } else {
    continuation.setTimeout(TimeUnit.SECONDS.toMillis(WORKER_TIMEOUT));
    continuation.suspend(resp);
    executorService.submit(new BackgroundTask(continuation));
 }



java.lang.IllegalStateException: IDLE,initial
at org.eclipse.jetty.server.AsyncContinuation.complete(AsyncContinuation.java:579) ~[na:na]
    at BackgroundTask.run() <-- This is the background worker...
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [na:1.7.0_67]
    at java.util.concurrent.FutureTask.run(Unknown Source) [na:1.7.0_67]
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.7.0_67] at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.7.0_67]
    at java.lang.Thread.run(Unknown Source) [na:1.7.0_67]

java.lang.IllegalStateException: REDISPATCHED,resumed,expired
at org.eclipse.jetty.server.AsyncContinuation.complete(AsyncContinuation.java:567) ~[na:na]
    at BackgroundTask.run() <-- This is the background worker...
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [na:1.7.0_67]
    at java.util.concurrent.FutureTask.run(Unknown Source) [na:1.7.0_67]
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.7.0_67] at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.7.0_67]
    at java.lang.Thread.run(Unknown Source) [na:1.7.0_67]


Back to the top