2012-06-18 13 views
10

Tengo un servidor Jetty que maneja solicitudes HTTP de larga ejecución: las respuestas son generadas por un proceso diferente X y terminan en un hash de coleccionista que Jetty solicita periódicamente.Cómo manejar la excepción Jetty: una solicitud HTTP de larga ejecución agota el tiempo de espera, pero el proceso al que llama nunca termina y Jetty no está satisfecho

Hay 3 casos:

  1. Proceso X termina antes del tiempo de espera de la petición HTTP - ningún problema
  2. Proceso X termina después del período de tiempo de espera de la solicitud - no problema
  3. El proceso X nunca termina, por debajo de la excepción ocurre

¿Cómo puedo detectar esta situación (3) y evitar la excepción mientras permitiendo que los otros dos casos funcionen correctamente?

Excepción:

2012-06-18 00:13:31.055:WARN:oejut.QueuedThreadPool: 
java.lang.IllegalStateException: IDLE,initial 
   at org.eclipse.jetty.server.AsyncContinuation.complete(AsyncContinuation.java:569) 
   at server.AsyncHTTPRequestProcessor.run(AsyncHTTPRequestProcessor.java:72) 
   at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1119) 
   at org.eclipse.jetty.server.AsyncContinuation$1.run(AsyncContinuation.java:875) 
   at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:599) 
   at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:534) 
   at java.lang.Thread.run(Thread.java:679) 


embarcadero continuación de una petición HTTP:

public class AsyncHTTPRequestProcessor implements Runnable { 

    private ConcurrentHashMap<String, String> collector; 
    private Logger logger; 
    private AsyncContext ctx; 
    //Defined this here because of strange behaviour when running junit 
    //tests and the response json string being empty... 
    private String responseStr = null; 

    public AsyncHTTPRequestProcessor(AsyncContext _ctx, 
      ConcurrentHashMap<String, String> _collector, Logger _logger) { 
     ctx = _ctx; 
     collector = _collector; 
     logger = _logger; 
    } 

    @Override 
    public void run() { 

     logger.info("AsyncContinuation start"); 

     //if(!((AsyncContinuation)ctx).isInitial()){ 
     String rid = (String) ctx.getRequest().getAttribute("rid"); 
     int elapsed = 0; 
     if(rid !=null) 
     { 

      logger.info("AsyncContinuation rid="+rid); 

      while(elapsed<ctx.getTimeout()) 
      { 
       if(collector.containsKey(rid)){ 
        responseStr = collector.get(rid); 
        collector.remove(rid); 

        logger.info("--->API http request in collector:"+responseStr); 
        ctx.getRequest().setAttribute("status",200); 
        ctx.getRequest().setAttribute("response", responseStr); 
        ctx.getRequest().setAttribute("endTime",System.currentTimeMillis()); 
        //ctx.complete(); 
        break; 
       } 
       try { 
        Thread.sleep(10); 
        elapsed+=10; 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      //} 
      logger.info("Collector in async stuff:"); 
      for(String key:collector.keySet()){ 
       logger.info(key+"->"+collector.get(key)); 
      } 

      for(Entry<String, String> x:collector.entrySet()){ 
       logger.info(x.getKey()+"->"+x.getValue()); 
      } 
      ctx.complete(); <---- this line 72 
     } 
    } 

} 
+0

Tengo el mismo problema. Estoy tratando de resolverlo. Tan pronto como pueda, daré una respuesta. –

+1

Si el proceso nunca termina, ¿cómo puede ocurrir la excepción? –

Respuesta

0

Usando bloque intento de captura podría ayudar en este caso.

try{ 
     ctx.complete() 
    } catch (IllegalStateException e){ 
     //Handle it the way you prefer. 
    } 
2

El problema aquí no es su llamada de AsyncContext # complete() sino el diseño general del código.

Continuaciones (lo mismo para Servlet async) está diseñado para ser asincrónico. El ciclo while que hace uso del tiempo de espera interno de continuaciones no debe estar aquí. Está transformando un diseño asíncrono en uno síncrono haciendo esto. Lo correcto es registrar un oyente utilizando Continuation # addContinuationListener() e implementa el método onTimeout() para procesar el tiempo de espera de manera apropiada.

Una vez que haya finalizado su lógica de tiempo de espera, le recomiendo mover la lógica del proceso X a la clase AsyncHTTPRequestProcessor y salir de la necesidad de utilizar un colector. Durante el procesamiento, debe suponer que el hilo actual nunca se agotará. Al hacer esto, su llamada para completar() tiene sentido y usted será inmune a problemas de concurrencia en el recopilador.

Cuestiones relacionadas